|
1 /* |
|
2 * Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: MsgEditorView implementation* |
|
15 */ |
|
16 |
|
17 |
|
18 |
|
19 // ========== INCLUDE FILES ================================ |
|
20 |
|
21 #include <eikenv.h> // for CEikonEnv |
|
22 #include <eikappui.h> // for CEikAppUi |
|
23 #include <barsread.h> // for TResourceReader |
|
24 #include <eikrted.h> // for CEikRichTextEditor |
|
25 #include <eikscrlb.h> |
|
26 #include <AknUtils.h> // for AknUtils |
|
27 #include <txtrich.h> // for automatic highlight |
|
28 #include <aknappui.h> |
|
29 #include <applayout.cdl.h> // LAF |
|
30 #include <aknlayoutscalable_apps.cdl.h> |
|
31 |
|
32 #include <bautils.h> // NearestLanguageFile |
|
33 #include <data_caging_path_literals.hrh> |
|
34 |
|
35 #include <aknnavi.h> |
|
36 #include <aknnavide.h> |
|
37 #include <AknStatuspaneUtils.h> |
|
38 |
|
39 #include <AknsBasicBackgroundControlContext.h> // for skins support |
|
40 #include <AknsDrawUtils.h> |
|
41 |
|
42 #include <MsgEditorAppUi.rsg> |
|
43 #include <StringLoader.h> |
|
44 |
|
45 #include "MsgEditorCommon.h" // |
|
46 #include "MsgEditorView.h" // for CMsgEditorView |
|
47 #include "MsgEditorObserver.h" // for MMsgEditorObserver |
|
48 #include "MsgHeader.h" // for CMsgHeader |
|
49 #include "MsgBody.h" // for CMsgBody |
|
50 #include "MsgExpandableControl.h" // for MsgExpandableControl |
|
51 #include "MsgBodyControl.h" // for MsgBodyControl |
|
52 #include "MsgAddressControl.h" // for MsgAddressControl |
|
53 #include "MsgAttachmentControl.h" // for MsgAttachmentControl |
|
54 #include "MsgAddressControlEditor.h" // for MsgAddressControlEditor |
|
55 #include "MsgEditorPanic.h" // for MsgEditor panics |
|
56 #include "MsgEditorLogging.h" |
|
57 |
|
58 // ========== EXTERNAL DATA STRUCTURES ===================== |
|
59 |
|
60 // ========== EXTERNAL FUNCTION PROTOTYPES ================= |
|
61 |
|
62 // ========== CONSTANTS ==================================== |
|
63 |
|
64 // ========== MACROS ======================================= |
|
65 |
|
66 // ========== LOCAL CONSTANTS AND MACROS =================== |
|
67 |
|
68 const TInt KMsgControlIndexHeader = 0; |
|
69 const TInt KMsgControlIndexBody = 1; |
|
70 const TInt KMsgNumberOfControls = 2; |
|
71 |
|
72 const TInt KMsgMaximumScrollPartLength = 64; |
|
73 _LIT( KMsgEditorAppUiResourceFileName, "msgeditorappui.rsc" ); |
|
74 |
|
75 // ========== MODULE DATA STRUCTURES ======================= |
|
76 |
|
77 // ========== LOCAL FUNCTION PROTOTYPES ==================== |
|
78 |
|
79 // ========== LOCAL FUNCTIONS ============================== |
|
80 |
|
81 // ========== MEMBER FUNCTIONS ============================= |
|
82 |
|
83 // --------------------------------------------------------- |
|
84 // CMsgEditorView::CMsgEditorView |
|
85 // |
|
86 // Constructor. |
|
87 // --------------------------------------------------------- |
|
88 // |
|
89 CMsgEditorView::CMsgEditorView( MMsgEditorObserver& aObserver, |
|
90 TUint32 aEditorModeFlags ): |
|
91 iEditorObserver( aObserver ), |
|
92 iCurrentFocus( EMsgNoneFocused ), |
|
93 iEditorModeFlags( aEditorModeFlags ), |
|
94 iLineHeight( MsgEditorCommons::MsgBaseLineDelta() ), |
|
95 iBaseLineOffset( MsgEditorCommons::MsgBaseLineOffset() ), |
|
96 iResourceLoader( *iCoeEnv ) |
|
97 { |
|
98 } |
|
99 |
|
100 // --------------------------------------------------------- |
|
101 // CMsgEditorView::ConstructL |
|
102 // |
|
103 // Constructs the editor view by creating the window, the header and the body. |
|
104 // --------------------------------------------------------- |
|
105 // |
|
106 void CMsgEditorView::ConstructL() |
|
107 { |
|
108 CreateWindowL(); |
|
109 |
|
110 if ( AknStatuspaneUtils::FlatLayoutActive() ) |
|
111 { |
|
112 CEikStatusPane* statusPane = iEikonEnv->AppUiFactory()->StatusPane(); |
|
113 if ( statusPane ) |
|
114 { |
|
115 CAknNavigationControlContainer* naviPane = |
|
116 static_cast<CAknNavigationControlContainer*>( statusPane->ControlL( |
|
117 TUid::Uid( EEikStatusPaneUidNavi ) ) ); |
|
118 |
|
119 if ( naviPane ) |
|
120 { |
|
121 naviPane->SetPreferredNaviDecoratorLayoutStyle( |
|
122 CAknNavigationDecorator::ENaviControlLayoutNormal ); |
|
123 } |
|
124 } |
|
125 } |
|
126 |
|
127 iBgContext = CAknsBasicBackgroundControlContext::NewL( KAknsIIDQsnBgAreaMainMessage, |
|
128 Rect(), |
|
129 EFalse ); |
|
130 |
|
131 // T9: Add control to stack to make FEP work. View does not accept key |
|
132 // events from CT9FepControl::HandleChangeInFocus(). Key events are |
|
133 // handled first by editor app ui which routes them to view. |
|
134 iEikonEnv->EikAppUi()->AddToStackL( this, |
|
135 ECoeStackPriorityDefault, |
|
136 ECoeStackFlagRefusesAllKeys ); |
|
137 |
|
138 Window().SetShadowDisabled( ETrue ); |
|
139 |
|
140 // Disables automatic background color drawing |
|
141 // on window server. |
|
142 Window().SetBackgroundColor(); |
|
143 |
|
144 CreateScrollBarL(); |
|
145 CreateHeaderL(); |
|
146 CreateBodyL(); |
|
147 } |
|
148 |
|
149 // --------------------------------------------------------- |
|
150 // CMsgEditorView::~CMsgEditorView |
|
151 // |
|
152 // Destructor. |
|
153 // --------------------------------------------------------- |
|
154 // |
|
155 EXPORT_C CMsgEditorView::~CMsgEditorView() |
|
156 { |
|
157 iEikonEnv->EikAppUi()->RemoveFromStack( this ); |
|
158 |
|
159 delete iHeader; |
|
160 delete iBody; |
|
161 delete iScrollBar; |
|
162 delete iBgContext; |
|
163 |
|
164 iResourceLoader.Close(); |
|
165 |
|
166 delete iScrollPopText; |
|
167 } |
|
168 |
|
169 // --------------------------------------------------------- |
|
170 // CMsgEditorView::NewL |
|
171 // |
|
172 // Factory method. |
|
173 // --------------------------------------------------------- |
|
174 // |
|
175 EXPORT_C CMsgEditorView* CMsgEditorView::NewL( MMsgEditorObserver& aObserver, |
|
176 TUint32 aEditorModeFlags ) |
|
177 { |
|
178 CMsgEditorView* self = new( ELeave ) CMsgEditorView( aObserver, aEditorModeFlags ); |
|
179 |
|
180 CleanupStack::PushL( self ); |
|
181 self->ConstructL(); |
|
182 CleanupStack::Pop( self ); |
|
183 |
|
184 return self; |
|
185 } |
|
186 |
|
187 // --------------------------------------------------------- |
|
188 // CMsgEditorView::MopNext |
|
189 // |
|
190 // From MObjectProvider. |
|
191 // --------------------------------------------------------- |
|
192 // |
|
193 EXPORT_C MObjectProvider* CMsgEditorView::MopNext() |
|
194 { |
|
195 return iEikonEnv->EikAppUi(); |
|
196 } |
|
197 |
|
198 // --------------------------------------------------------- |
|
199 // CMsgEditorView::ExecuteL |
|
200 // |
|
201 // Prepares the editor view for showing it on the screen. |
|
202 // --------------------------------------------------------- |
|
203 // |
|
204 EXPORT_C void CMsgEditorView::ExecuteL( const TRect& aRect, |
|
205 TInt aControlIdForFocus ) |
|
206 { |
|
207 TRect rect( aRect ); |
|
208 rect.iBr.iY = rect.iTl.iY + MsgEditorCommons::EditorViewHeigth(); |
|
209 |
|
210 AdjustComponentDistances(); |
|
211 |
|
212 SetViewRect( rect ); |
|
213 iSize = rect.Size(); |
|
214 |
|
215 // Set initial size for controls. |
|
216 TSize editorSize( rect.Size() ); |
|
217 SetAndGetSizeL( editorSize, ETrue ); |
|
218 |
|
219 // Enable here so that size affecting events are processed |
|
220 // from header & body controls after this point. |
|
221 iStateFlags |= EMsgStateInitializing; |
|
222 |
|
223 SizeChanged(); |
|
224 ActivateL(); |
|
225 |
|
226 iScrollParts = 1; |
|
227 |
|
228 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgScrollParts, |
|
229 &iScrollParts, |
|
230 NULL, |
|
231 NULL ); |
|
232 |
|
233 if ( aControlIdForFocus != EMsgComponentIdNull ) |
|
234 { |
|
235 SetFocusByControlIdL( aControlIdForFocus ); |
|
236 } |
|
237 |
|
238 if ( aControlIdForFocus == EMsgComponentIdNull || |
|
239 iCurrentFocus == EMsgNoneFocused ) |
|
240 { |
|
241 iCurrentFocus = EMsgHeaderFocused; |
|
242 |
|
243 TInt newFocus = iHeader->FirstFocusableControl( 0, EMsgFocusDown ); |
|
244 if ( newFocus == KErrNotFound ) |
|
245 { |
|
246 iCurrentFocus = EMsgBodyFocused; |
|
247 newFocus = iBody->FirstFocusableControl( 0, EMsgFocusDown ); |
|
248 |
|
249 if ( newFocus == KErrNotFound ) |
|
250 { |
|
251 iCurrentFocus = EMsgNoneFocused; |
|
252 } |
|
253 else |
|
254 { |
|
255 iBody->ChangeFocusTo( newFocus, ENoDrawNow ); |
|
256 } |
|
257 } |
|
258 else |
|
259 { |
|
260 iHeader->ChangeFocusTo( newFocus, ENoDrawNow ); |
|
261 } |
|
262 } |
|
263 |
|
264 UpdateScrollBarL(); |
|
265 |
|
266 SetComponentsInitialized(); |
|
267 |
|
268 iStateFlags &= ~EMsgStateInitializing; |
|
269 iStateFlags |= EMsgStateInitialized; |
|
270 |
|
271 // Has to be called after EMsgStateInitialized flag is set on since |
|
272 // otherwise control that have suppress text formatting are not |
|
273 // resized correctly. |
|
274 NotifyControlsForEvent( EMsgViewEventPrepareForViewing, 0 ); |
|
275 |
|
276 DrawNow(); |
|
277 iCoeEnv->WsSession().Flush(); |
|
278 } |
|
279 |
|
280 // --------------------------------------------------------- |
|
281 // CMsgEditorView::ControlById |
|
282 // |
|
283 // Finds a control from the header and the body by id and returns a pointer to it. |
|
284 // --------------------------------------------------------- |
|
285 // |
|
286 EXPORT_C CMsgBaseControl* CMsgEditorView::ControlById( TInt aControlId ) const |
|
287 { |
|
288 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
289 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
290 |
|
291 CMsgBaseControl* component = iHeader->Component( aControlId ); |
|
292 |
|
293 if ( !component ) |
|
294 { |
|
295 component = iBody->Component( aControlId ); |
|
296 } |
|
297 |
|
298 return component; |
|
299 } |
|
300 |
|
301 // --------------------------------------------------------- |
|
302 // CMsgEditorView::FocusedControl |
|
303 // |
|
304 // Returns a pointer to a focused control. If no control is focused, returns NULL. |
|
305 // --------------------------------------------------------- |
|
306 // |
|
307 EXPORT_C CMsgBaseControl* CMsgEditorView::FocusedControl() const |
|
308 { |
|
309 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
310 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
311 |
|
312 if ( iCurrentFocus == EMsgHeaderFocused ) |
|
313 { |
|
314 return iHeader->FocusedControl(); |
|
315 } |
|
316 else if ( iCurrentFocus == EMsgBodyFocused ) |
|
317 { |
|
318 return iBody->FocusedControl(); |
|
319 } |
|
320 else |
|
321 { |
|
322 return NULL; |
|
323 } |
|
324 } |
|
325 |
|
326 // --------------------------------------------------------- |
|
327 // CMsgEditorView::SetFocus |
|
328 // |
|
329 // Sets focus to a control aControlId. |
|
330 // --------------------------------------------------------- |
|
331 // |
|
332 EXPORT_C void CMsgEditorView::SetFocus( TInt aControlId ) |
|
333 { |
|
334 __ASSERT_DEBUG( iStateFlags & EMsgStateInitialized, |
|
335 Panic( EMsgFunctionCalledBeforeInitialization ) ); |
|
336 |
|
337 TRAP_IGNORE( |
|
338 { |
|
339 SetFocusByControlIdL( aControlId ); |
|
340 UpdateScrollBarL(); |
|
341 } ); |
|
342 } |
|
343 |
|
344 // --------------------------------------------------------- |
|
345 // CMsgEditorView::AddControlFromResourceL |
|
346 // |
|
347 // Constructs a control of type aControlType from resource and adds it to |
|
348 // a form component aFormComponent. The control is added to a position aIndex. |
|
349 // |
|
350 // Leaves with KErrNotFound if aControlType is incorrect. |
|
351 // --------------------------------------------------------- |
|
352 // |
|
353 EXPORT_C TInt CMsgEditorView::AddControlFromResourceL( TInt aResourceId, |
|
354 TInt aControlType, |
|
355 TInt aIndex, |
|
356 TMsgFormComponent aFormComponent ) |
|
357 { |
|
358 CMsgBaseControl* control = NULL; |
|
359 |
|
360 switch (aControlType) |
|
361 { |
|
362 case EMsgExpandableControl: |
|
363 { |
|
364 control = new ( ELeave ) CMsgExpandableControl( *this ); |
|
365 break; |
|
366 } |
|
367 case EMsgAddressControl: |
|
368 { |
|
369 control = new ( ELeave ) CMsgAddressControl( *this ); |
|
370 break; |
|
371 } |
|
372 case EMsgAttachmentControl: |
|
373 { |
|
374 control = new ( ELeave ) CMsgAttachmentControl( *this, *this ); |
|
375 break; |
|
376 } |
|
377 default: |
|
378 { |
|
379 control = iEditorObserver.CreateCustomControlL( aControlType ); |
|
380 if ( control == NULL ) |
|
381 { |
|
382 User::Leave( KErrNotSupported ); |
|
383 } |
|
384 break; |
|
385 } |
|
386 } |
|
387 |
|
388 CleanupStack::PushL( control ); |
|
389 control->SetControlType( aControlType ); |
|
390 control->SetMopParent( this ); |
|
391 |
|
392 control->ConstructFromResourceL( aResourceId ); |
|
393 |
|
394 TInt controlId = control->ControlId(); |
|
395 DoAddControlL( control, controlId, aIndex, aFormComponent ); |
|
396 CleanupStack::Pop(); //control |
|
397 |
|
398 return controlId; |
|
399 } |
|
400 |
|
401 // --------------------------------------------------------- |
|
402 // CMsgEditorView::AddControlL |
|
403 // |
|
404 // Adds a control given by aControl to a form component aFormComponent. |
|
405 // The control is added to a position aIndex with control id aControlId. |
|
406 // --------------------------------------------------------- |
|
407 // |
|
408 EXPORT_C void CMsgEditorView::AddControlL( CMsgBaseControl* aControl, |
|
409 TInt aControlId, |
|
410 TInt aIndex, |
|
411 TMsgFormComponent aFormComponent ) |
|
412 { |
|
413 DoAddControlL( aControl, aControlId, aIndex, aFormComponent ); |
|
414 } |
|
415 |
|
416 // --------------------------------------------------------- |
|
417 // CMsgEditorView::RemoveControlL |
|
418 // |
|
419 // Removes the control aControlId from the header or the body and returns pointer |
|
420 // to it. If a control cannot be found, returns NULL. |
|
421 // --------------------------------------------------------- |
|
422 // |
|
423 EXPORT_C CMsgBaseControl* CMsgEditorView::RemoveControlL( TInt aControlId ) |
|
424 { |
|
425 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
426 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
427 |
|
428 if ( iStateFlags & EMsgStateInitialized ) // Control is removed on run-time. |
|
429 { |
|
430 if ( FocusedControl() == ControlById( aControlId ) && |
|
431 iHeader->CountMsgControls() + iBody->CountMsgControls() > 1 ) |
|
432 { |
|
433 // Try to move focus to different control as focused control is removed and |
|
434 // there is more than one control loaded. |
|
435 MMsgEditorObserver::TMsgFocusEvent focusEvent = MMsgEditorObserver::EMsgFocusNone; |
|
436 |
|
437 if ( !RotateFocusL( EMsgFocusUp, focusEvent ) ) |
|
438 { |
|
439 if ( !RotateFocusL( EMsgFocusDown, focusEvent ) ) |
|
440 { |
|
441 //__ASSERT_DEBUG(EFalse, Panic(EMsgFocusLost)); |
|
442 // There are no focusing component left. Remove the focus from current control. |
|
443 FocusedControl()->SetFocus( EFalse ); |
|
444 } |
|
445 } |
|
446 |
|
447 iCoeEnv->SyncNotifyFocusObserversOfChangeInFocus(); |
|
448 } |
|
449 } |
|
450 |
|
451 // Remove a component from the header. |
|
452 CMsgBaseControl* control = iHeader->RemoveControlL( aControlId ); |
|
453 |
|
454 if ( control == NULL ) |
|
455 { |
|
456 // If a component could not be found in the header, remove it from the body. |
|
457 control = iBody->RemoveControlL( aControlId ); |
|
458 } |
|
459 |
|
460 if ( iStateFlags & EMsgStateInitialized ) // Control is removed on run-time. |
|
461 { |
|
462 if ( control != NULL ) |
|
463 { |
|
464 CleanupStack::PushL( control ); |
|
465 RefreshViewL(); |
|
466 EnsureCorrectViewPosition(); |
|
467 CleanupStack::Pop(); // control |
|
468 } |
|
469 } |
|
470 else if ( iHeader->CountMsgControls() == 0 ) |
|
471 { |
|
472 iFormOffset = 0; |
|
473 } |
|
474 |
|
475 if ( control ) |
|
476 { |
|
477 // This is needed atleast for japanese pictographs to not |
|
478 // draw into current control area. |
|
479 control->MakeVisible( EFalse ); |
|
480 } |
|
481 |
|
482 return control; |
|
483 } |
|
484 |
|
485 // --------------------------------------------------------- |
|
486 // CMsgEditorView::DeleteControlL |
|
487 // |
|
488 // Removes the control aControlId from the header or the body and returns pointer |
|
489 // to it. If a control cannot be found, returns NULL. |
|
490 // --------------------------------------------------------- |
|
491 // |
|
492 EXPORT_C void CMsgEditorView::DeleteControlL( TInt aControlId ) |
|
493 { |
|
494 CMsgBaseControl* baseControl = RemoveControlL( aControlId ); |
|
495 delete baseControl; |
|
496 } |
|
497 |
|
498 // --------------------------------------------------------- |
|
499 // CMsgEditorView::FormComponent |
|
500 // |
|
501 // Returns a reference to a form component. |
|
502 // --------------------------------------------------------- |
|
503 // |
|
504 EXPORT_C CCoeControl& CMsgEditorView::FormComponent( TMsgFormComponent aFormComponent ) const |
|
505 { |
|
506 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
507 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
508 |
|
509 switch ( aFormComponent ) |
|
510 { |
|
511 case EMsgHeader: |
|
512 { |
|
513 return *iHeader; |
|
514 } |
|
515 case EMsgBody: |
|
516 { |
|
517 return *iBody; |
|
518 } |
|
519 default: |
|
520 { |
|
521 __ASSERT_DEBUG( EFalse, Panic( EMsgIncorrectFormComponent ) ); |
|
522 // Just to make compiler happy. |
|
523 return *iBody; |
|
524 } |
|
525 } |
|
526 } |
|
527 |
|
528 // --------------------------------------------------------- |
|
529 // CMsgEditorView::HandleScreenSizeChangeL |
|
530 // |
|
531 // Prepares the editor view for viewing it on the screen after screen size change. |
|
532 // --------------------------------------------------------- |
|
533 // |
|
534 EXPORT_C void CMsgEditorView::HandleScreenSizeChangeL( const TRect& aRect ) |
|
535 { |
|
536 __ASSERT_DEBUG( iStateFlags & EMsgStateInitialized, |
|
537 Panic( EMsgFunctionCalledBeforeInitialization ) ); |
|
538 |
|
539 SetViewRect( aRect ); |
|
540 RefreshViewL(); |
|
541 } |
|
542 |
|
543 |
|
544 // --------------------------------------------------------- |
|
545 // CMsgEditorView::ResetControls |
|
546 // |
|
547 // Reset all controls. |
|
548 // --------------------------------------------------------- |
|
549 // |
|
550 EXPORT_C void CMsgEditorView::ResetControls() |
|
551 { |
|
552 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
553 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
554 |
|
555 iHeader->ResetControls(); |
|
556 iBody->ResetControls(); |
|
557 } |
|
558 |
|
559 // --------------------------------------------------------- |
|
560 // CMsgEditorView::ResetControls |
|
561 // |
|
562 // Reset controls from header or body. |
|
563 // --------------------------------------------------------- |
|
564 // |
|
565 EXPORT_C void CMsgEditorView::ResetControls( TMsgFormComponent aFormComponent ) |
|
566 { |
|
567 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
568 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
569 |
|
570 switch ( aFormComponent ) |
|
571 { |
|
572 case EMsgHeader: |
|
573 { |
|
574 iHeader->ResetControls(); |
|
575 break; |
|
576 } |
|
577 case EMsgBody: |
|
578 { |
|
579 iBody->ResetControls(); |
|
580 break; |
|
581 } |
|
582 default: |
|
583 { |
|
584 __ASSERT_DEBUG( EFalse, Panic( EMsgIncorrectFormComponent ) ); |
|
585 } |
|
586 } |
|
587 } |
|
588 |
|
589 // --------------------------------------------------------- |
|
590 // CMsgEditorView::IsAnyControlModified |
|
591 // |
|
592 // Checks if any control owned by view is modified. |
|
593 // --------------------------------------------------------- |
|
594 // |
|
595 EXPORT_C TBool CMsgEditorView::IsAnyControlModified() const |
|
596 { |
|
597 TInt i; |
|
598 CMsgBaseControl* ctrl; |
|
599 TInt countHeader = iHeader->CountMsgControls(); |
|
600 TInt countBody = iBody->CountMsgControls(); |
|
601 |
|
602 for ( i = 0; i < countHeader; i++ ) |
|
603 { |
|
604 ctrl = iHeader->MsgControl( i ); |
|
605 if ( ctrl && ctrl->IsModified() ) |
|
606 { |
|
607 return ETrue; |
|
608 } |
|
609 } |
|
610 |
|
611 for ( i = 0; i < countBody; i++ ) |
|
612 { |
|
613 ctrl = iBody->MsgControl( i ); |
|
614 if ( ctrl && ctrl->IsModified() ) |
|
615 { |
|
616 return ETrue; |
|
617 } |
|
618 } |
|
619 |
|
620 return EFalse; |
|
621 } |
|
622 |
|
623 // --------------------------------------------------------- |
|
624 // CMsgEditorView::SetControlsModified |
|
625 // |
|
626 // Updates modified flag of controls owned by view. |
|
627 // --------------------------------------------------------- |
|
628 // |
|
629 EXPORT_C void CMsgEditorView::SetControlsModified( TBool aFlag ) |
|
630 { |
|
631 TInt i; |
|
632 CMsgBaseControl* ctrl; |
|
633 TInt countHeader = iHeader->CountMsgControls(); |
|
634 TInt countBody = iBody->CountMsgControls(); |
|
635 |
|
636 for ( i = 0; i < countHeader; i++ ) |
|
637 { |
|
638 ctrl = iHeader->MsgControl( i ); |
|
639 if ( ctrl ) |
|
640 { |
|
641 ctrl->SetModified( aFlag ); |
|
642 } |
|
643 } |
|
644 |
|
645 for ( i = 0; i < countBody; i++ ) |
|
646 { |
|
647 ctrl = iBody->MsgControl( i ); |
|
648 if ( ctrl ) |
|
649 { |
|
650 ctrl->SetModified( aFlag ); |
|
651 } |
|
652 } |
|
653 } |
|
654 |
|
655 // --------------------------------------------------------- |
|
656 // CMsgEditorView::OfferKeyEventL |
|
657 // |
|
658 // Handles key events. |
|
659 // --------------------------------------------------------- |
|
660 // |
|
661 EXPORT_C TKeyResponse CMsgEditorView::OfferKeyEventL( const TKeyEvent& aKeyEvent, |
|
662 TEventCode aType ) |
|
663 { |
|
664 CMsgBaseControl* ctrl = FocusedControl(); |
|
665 |
|
666 // Is this needed? |
|
667 if ( ctrl && ctrl->ControlType() == EMsgAddressControl && aType == EEventKeyUp ) |
|
668 { |
|
669 return ctrl->OfferKeyEventL( aKeyEvent, aType ); |
|
670 } |
|
671 |
|
672 if ( ( !( iStateFlags & EMsgStateInitialized ) ) || ( aType != EEventKey ) ) |
|
673 { |
|
674 return EKeyWasNotConsumed; |
|
675 } |
|
676 |
|
677 TKeyResponse keyResp( EKeyWasNotConsumed ); |
|
678 TBool focusRotated = EFalse; |
|
679 TBool forceScrollUp = EFalse; |
|
680 MMsgEditorObserver::TMsgFocusEvent focusEvent = MMsgEditorObserver::EMsgFocusNone; |
|
681 |
|
682 switch ( aKeyEvent.iCode ) |
|
683 { |
|
684 case EKeyUpArrow: |
|
685 { |
|
686 if ( ctrl ) |
|
687 { |
|
688 // No focus change allowed if selection is ongoing. |
|
689 if ( !( aKeyEvent.iModifiers & EModifierShift ) && |
|
690 ctrl->IsFocusChangePossible( EMsgFocusUp ) ) |
|
691 { |
|
692 if ( RotateFocusL( EMsgFocusUp, focusEvent ) ) |
|
693 { |
|
694 focusRotated = ETrue; |
|
695 keyResp = EKeyWasConsumed; // focus changed. |
|
696 } |
|
697 else |
|
698 { |
|
699 // the cursor is in the topmost control. |
|
700 TInt delta = -iFormOffset; |
|
701 ScrollForm( delta, ETrue ); |
|
702 |
|
703 keyResp = EKeyWasNotConsumed; |
|
704 } |
|
705 } |
|
706 } |
|
707 else |
|
708 { |
|
709 // no focused control: set focus event if many parts. |
|
710 if ( iScrollParts > 1 ) |
|
711 { |
|
712 focusEvent = MMsgEditorObserver::EMsgFocusAtTop; |
|
713 } |
|
714 } |
|
715 break; |
|
716 } |
|
717 case EKeyDownArrow: |
|
718 { |
|
719 if ( ctrl ) |
|
720 { |
|
721 // No focus change allowed if selection is ongoing. |
|
722 if ( !( aKeyEvent.iModifiers & EModifierShift ) && |
|
723 ctrl->IsFocusChangePossible( EMsgFocusDown ) ) |
|
724 { |
|
725 if ( RotateFocusL( EMsgFocusDown, focusEvent ) ) |
|
726 { |
|
727 focusRotated = ETrue; |
|
728 keyResp = EKeyWasConsumed; |
|
729 } |
|
730 else |
|
731 { |
|
732 keyResp = EKeyWasNotConsumed; |
|
733 } |
|
734 } |
|
735 } |
|
736 else |
|
737 { |
|
738 // no focused control: set focus event if many parts. |
|
739 if ( iScrollParts > 1 ) |
|
740 { |
|
741 focusEvent = MMsgEditorObserver::EMsgFocusAtBottom; |
|
742 } |
|
743 } |
|
744 break; |
|
745 } |
|
746 default: |
|
747 { |
|
748 break; |
|
749 } |
|
750 } |
|
751 |
|
752 if ( ctrl && keyResp == EKeyWasNotConsumed ) |
|
753 { |
|
754 keyResp = ctrl->OfferKeyEventL( aKeyEvent, aType ); |
|
755 } |
|
756 |
|
757 if ( focusEvent != MMsgEditorObserver::EMsgFocusNone ) |
|
758 { |
|
759 MMsgEditorObserver::TMsgAfterFocusEventFunc after = |
|
760 MMsgEditorObserver::EMsgAfterFocusNone; |
|
761 |
|
762 #ifdef RD_SCALABLE_UI_V2 |
|
763 if ( focusEvent == MMsgEditorObserver::EMsgFocusAtTop ) |
|
764 { |
|
765 iVisiblePart--; |
|
766 } |
|
767 else if ( focusEvent == MMsgEditorObserver::EMsgFocusAtBottom ) |
|
768 { |
|
769 iVisiblePart++; |
|
770 } |
|
771 |
|
772 iVisiblePart = Max( 0, Min( iScrollParts - 1, iVisiblePart ) ); |
|
773 #endif |
|
774 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgHandleFocusChange, |
|
775 &focusEvent, |
|
776 &after, |
|
777 &iVisiblePart ); |
|
778 |
|
779 if ( after != MMsgEditorObserver::EMsgAfterFocusNone ) |
|
780 { |
|
781 forceScrollUp = SetAfterFocusL( after ); |
|
782 } |
|
783 } |
|
784 |
|
785 EnsureCorrectFormPosition( ( aKeyEvent.iCode == EKeyDownArrow ) && focusRotated, forceScrollUp ); |
|
786 |
|
787 UpdateScrollBarL(); |
|
788 |
|
789 return keyResp; |
|
790 } |
|
791 |
|
792 // --------------------------------------------------------- |
|
793 // CMsgEditorView::HandlePointerEventL |
|
794 // |
|
795 // Handles pointer event processing and propagation. |
|
796 // --------------------------------------------------------- |
|
797 // |
|
798 #ifdef RD_SCALABLE_UI_V2 |
|
799 void CMsgEditorView::HandlePointerEventL( const TPointerEvent& aPointerEvent ) |
|
800 { |
|
801 if ( AknLayoutUtils::PenEnabled() ) |
|
802 { |
|
803 TBool handled( EFalse ); |
|
804 |
|
805 if ( IsFocused() ) |
|
806 { |
|
807 TPointerEvent pointerEvent( aPointerEvent ); |
|
808 |
|
809 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgControlPointerEvent, |
|
810 ControlFromPosition( aPointerEvent.iPosition, ETrue ), |
|
811 &pointerEvent, |
|
812 &handled ); |
|
813 } |
|
814 |
|
815 if ( !handled ) |
|
816 { |
|
817 CCoeControl::HandlePointerEventL( aPointerEvent ); |
|
818 } |
|
819 } |
|
820 } |
|
821 #else |
|
822 void CMsgEditorView::HandlePointerEventL( const TPointerEvent& /*aPointerEvent*/ ) |
|
823 { |
|
824 } |
|
825 #endif // RD_SCALABLE_UI_V2 |
|
826 |
|
827 |
|
828 // --------------------------------------------------------- |
|
829 // CMsgEditorView::ViewInitialized |
|
830 // |
|
831 // Returns whether view is initialized. |
|
832 // --------------------------------------------------------- |
|
833 // |
|
834 TBool CMsgEditorView::ViewInitialized() const |
|
835 { |
|
836 return iStateFlags & EMsgStateInitialized; |
|
837 } |
|
838 |
|
839 // --------------------------------------------------------- |
|
840 // CMsgEditorView::ViewRect |
|
841 // |
|
842 // Returns the current view rectangle. |
|
843 // --------------------------------------------------------- |
|
844 // |
|
845 TRect CMsgEditorView::ViewRect() const |
|
846 { |
|
847 return iViewRect; |
|
848 } |
|
849 |
|
850 // --------------------------------------------------------- |
|
851 // CMsgEditorView::HandleBaseControlEventRequestL |
|
852 // |
|
853 // Handles an event from a control. |
|
854 // --------------------------------------------------------- |
|
855 // |
|
856 TBool CMsgEditorView::HandleBaseControlEventRequestL( CMsgBaseControl* aControl, |
|
857 TMsgControlEventRequest aRequest, |
|
858 TInt aDelta ) |
|
859 { |
|
860 if ( !( iStateFlags & EMsgStateInitialized ) ) |
|
861 { |
|
862 // Allow processing of possible height & position changing |
|
863 // events when view is currently being initialized. |
|
864 if ( !( iStateFlags & EMsgStateInitializing ) || |
|
865 !( aRequest == EMsgEnsureCorrectFormPosition || |
|
866 aRequest == EMsgHeightChanged ) ) |
|
867 { |
|
868 return ETrue; |
|
869 } |
|
870 } |
|
871 |
|
872 TBool done( EFalse ); |
|
873 MMsgEditorObserver::TMsgFocusEvent focusEvent = MMsgEditorObserver::EMsgFocusNone; |
|
874 |
|
875 switch ( aRequest ) |
|
876 { |
|
877 case EMsgCheckIfFocusIsAboveThis: |
|
878 { |
|
879 TBool isAbove = EFalse; |
|
880 TInt componentIndex = iHeader->ComponentIndexFromId( aControl->ControlId() ); |
|
881 if ( componentIndex != KErrNotFound ) |
|
882 { |
|
883 // control found in header. |
|
884 isAbove = iCurrentFocus == EMsgHeaderFocused |
|
885 ? iHeader->CurrentFocus() < componentIndex |
|
886 : EFalse; |
|
887 } |
|
888 else |
|
889 { |
|
890 // control found in body. |
|
891 componentIndex = iBody->ComponentIndexFromId( aControl->ControlId() ); |
|
892 isAbove = iCurrentFocus == EMsgBodyFocused |
|
893 ? iBody->CurrentFocus() < componentIndex |
|
894 : ETrue; |
|
895 } |
|
896 return isAbove; |
|
897 } |
|
898 |
|
899 case EMsgEnsureCorrectFormPosition: |
|
900 { |
|
901 if ( iStateFlags & EMsgEnsureCorrectFormPositionRequestIssued ) |
|
902 { |
|
903 // prevents recursion. |
|
904 return EFalse; |
|
905 } |
|
906 break; |
|
907 } |
|
908 case EMsgRotateFocusUp: |
|
909 { |
|
910 done = RotateFocusL( EMsgFocusUp, focusEvent ); |
|
911 break; |
|
912 } |
|
913 case EMsgRotateFocusDown: |
|
914 { |
|
915 done = RotateFocusL( EMsgFocusDown, focusEvent ); |
|
916 break; |
|
917 } |
|
918 case EMsgHeightChanged: |
|
919 { |
|
920 if ( iStateFlags & EMsgStateRefreshing ) |
|
921 { |
|
922 done = ETrue; |
|
923 } |
|
924 else if ( aControl && |
|
925 aControl->ControlModeFlags() & EMsgControlModeBodyMaxHeight ) |
|
926 { |
|
927 // Special handling is needed when maximum height body control's height is changed. |
|
928 // Currently this is happening when control is reseted. Special handling is |
|
929 // needed as last line of body control's text should be shown on the |
|
930 // last visible editor line if editor total height permits it. If editor total |
|
931 // does not permit this then editor should show it's topmost line. |
|
932 TInt bottomYPos( aControl->Position().iY + aControl->VirtualHeight() ); |
|
933 TInt distanceFromBottom( Rect().iBr.iY - bottomYPos ); |
|
934 |
|
935 if ( distanceFromBottom > 0 ) |
|
936 { |
|
937 TInt delta = Abs( iFormOffset ) < distanceFromBottom ? -iFormOffset : |
|
938 distanceFromBottom; |
|
939 |
|
940 if ( delta ) |
|
941 { |
|
942 ScrollForm( delta, ETrue ); |
|
943 } |
|
944 } |
|
945 |
|
946 if ( ViewInitialized() ) |
|
947 { |
|
948 UpdateScrollBarL(); |
|
949 } |
|
950 |
|
951 done = ETrue; |
|
952 } |
|
953 else |
|
954 { |
|
955 done = HandleHeightChangedL( aControl, aDelta ); |
|
956 |
|
957 if ( ViewInitialized() ) |
|
958 { |
|
959 UpdateScrollBarL(); |
|
960 } |
|
961 } |
|
962 return done; |
|
963 } |
|
964 case EMsgScrollForm: |
|
965 { |
|
966 done = ScrollForm( aDelta, ETrue ); |
|
967 break; |
|
968 } |
|
969 case EMsgUpdateScrollbar: |
|
970 { |
|
971 UpdateScrollBarL(); |
|
972 return ETrue; |
|
973 } |
|
974 default: |
|
975 { |
|
976 break; |
|
977 } |
|
978 } |
|
979 |
|
980 done = EnsureCorrectFormPosition( EFalse ); |
|
981 |
|
982 if ( iStateFlags & EMsgStateRefreshing || |
|
983 iStateFlags & EMsgStateInitializing ) |
|
984 { |
|
985 return done; |
|
986 } |
|
987 |
|
988 UpdateScrollBarL(); |
|
989 |
|
990 return done; |
|
991 } |
|
992 |
|
993 // --------------------------------------------------------- |
|
994 // CMsgEditorView::HandleBaseControlEventRequestL |
|
995 // |
|
996 // Handles an event from a control. |
|
997 // --------------------------------------------------------- |
|
998 // |
|
999 TBool CMsgEditorView::HandleBaseControlEventRequestL( CMsgBaseControl* aControl, |
|
1000 TMsgControlEventRequest aRequest ) |
|
1001 { |
|
1002 return HandleBaseControlEventRequestL( aControl, aRequest, 0 ); |
|
1003 } |
|
1004 |
|
1005 // --------------------------------------------------------- |
|
1006 // CMsgEditorView::HandleEditObserverEventRequestL |
|
1007 // |
|
1008 // Handles an event from a control. |
|
1009 // --------------------------------------------------------- |
|
1010 // |
|
1011 TInt CMsgEditorView::HandleEditObserverEventRequestL( const CCoeControl* /*aControl*/, |
|
1012 TMsgControlEventRequest aRequest, |
|
1013 TAny* aArg1, |
|
1014 TAny* aArg2, |
|
1015 TAny* aArg3 ) |
|
1016 { |
|
1017 switch ( aRequest ) |
|
1018 { |
|
1019 case EMsgDenyCut: |
|
1020 { |
|
1021 CEikEdwin::TClipboardFunc cb = CEikEdwin::ECut; |
|
1022 TInt arg = 0; |
|
1023 |
|
1024 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgDenyClipboardOperation, |
|
1025 &cb, |
|
1026 &arg, |
|
1027 NULL ); |
|
1028 return arg; |
|
1029 } |
|
1030 case EMsgDenyCopy: |
|
1031 { |
|
1032 CEikEdwin::TClipboardFunc cb = CEikEdwin::ECopy; |
|
1033 TInt arg = 0; |
|
1034 |
|
1035 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgDenyClipboardOperation, |
|
1036 &cb, |
|
1037 &arg, |
|
1038 NULL ); |
|
1039 return arg; |
|
1040 } |
|
1041 case EMsgDenyPaste: |
|
1042 { |
|
1043 CEikEdwin::TClipboardFunc cb = CEikEdwin::EPaste; |
|
1044 TInt arg = 0; |
|
1045 |
|
1046 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgDenyClipboardOperation, |
|
1047 &cb, |
|
1048 &arg, |
|
1049 NULL ); |
|
1050 return arg; |
|
1051 } |
|
1052 case EMsgStateFlags: |
|
1053 { |
|
1054 return iStateFlags; |
|
1055 } |
|
1056 case EMsgGetNaviIndicators: |
|
1057 { |
|
1058 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgGetNaviIndicators, |
|
1059 aArg1, |
|
1060 aArg2, |
|
1061 aArg3 ); |
|
1062 return 0; |
|
1063 } |
|
1064 case EMsgButtonPressed: |
|
1065 { |
|
1066 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgButtonEvent, |
|
1067 aArg1, |
|
1068 aArg2, |
|
1069 aArg3 ); |
|
1070 return 0; |
|
1071 } |
|
1072 default: |
|
1073 { |
|
1074 break; |
|
1075 } |
|
1076 } |
|
1077 return 0; |
|
1078 } |
|
1079 |
|
1080 // --------------------------------------------------------- |
|
1081 // CMsgEditorView::CountComponentControls |
|
1082 // |
|
1083 // Returns a number of controls. |
|
1084 // --------------------------------------------------------- |
|
1085 // |
|
1086 TInt CMsgEditorView::CountComponentControls() const |
|
1087 { |
|
1088 TInt countScrollBarComponents( 0 ); |
|
1089 |
|
1090 if ( iScrollBar ) |
|
1091 { |
|
1092 countScrollBarComponents = iScrollBar->CountComponentControls(); |
|
1093 } |
|
1094 |
|
1095 return KMsgNumberOfControls + countScrollBarComponents; |
|
1096 } |
|
1097 |
|
1098 // --------------------------------------------------------- |
|
1099 // CMsgEditorView::ComponentControl |
|
1100 // |
|
1101 // Returns a control of index aIndex. |
|
1102 // --------------------------------------------------------- |
|
1103 // |
|
1104 CCoeControl* CMsgEditorView::ComponentControl( TInt aIndex ) const |
|
1105 { |
|
1106 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1107 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1108 |
|
1109 TInt countScrollBarComponents( 0 ); |
|
1110 |
|
1111 if ( iScrollBar ) |
|
1112 { |
|
1113 countScrollBarComponents = iScrollBar->CountComponentControls(); |
|
1114 } |
|
1115 |
|
1116 switch ( aIndex ) |
|
1117 { |
|
1118 case KMsgControlIndexHeader: |
|
1119 { |
|
1120 return iHeader; |
|
1121 } |
|
1122 case KMsgControlIndexBody: |
|
1123 { |
|
1124 return iBody; |
|
1125 } |
|
1126 default: |
|
1127 { |
|
1128 if ( iScrollBar && |
|
1129 aIndex >= KMsgNumberOfControls && |
|
1130 aIndex < countScrollBarComponents + KMsgNumberOfControls ) |
|
1131 { |
|
1132 return iScrollBar->ComponentControl( aIndex - KMsgNumberOfControls ); |
|
1133 } |
|
1134 else |
|
1135 { |
|
1136 __ASSERT_DEBUG( EFalse, Panic( EMsgIncorrectComponentIndex ) ); |
|
1137 } |
|
1138 return NULL; |
|
1139 } |
|
1140 } |
|
1141 } |
|
1142 |
|
1143 // --------------------------------------------------------- |
|
1144 // CMsgEditorView::SizeChanged |
|
1145 // |
|
1146 // Sets new position for all the controls. |
|
1147 // --------------------------------------------------------- |
|
1148 // |
|
1149 void CMsgEditorView::SizeChanged() |
|
1150 { |
|
1151 MEBLOGGER_ENTERFN( "CMsgEditorView::SizeChanged" ); |
|
1152 |
|
1153 if ( iBgContext ) |
|
1154 { |
|
1155 iBgContext->SetRect( Rect() ); |
|
1156 iBgContext->SetParentPos( PositionRelativeToScreen() ); |
|
1157 } |
|
1158 |
|
1159 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1160 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1161 |
|
1162 TPoint bodyPosition( MsgEditorCommons::MsgBodyPane().iTl.iX, 0 ); |
|
1163 TPoint headerPosition( MsgEditorCommons::MsgHeaderPane().iTl.iX, iFormOffset ); |
|
1164 |
|
1165 //MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::SizeChanged: header height %d "), iHeader->Size().iHeight); |
|
1166 //MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::SizeChanged: body height %d "), iBody->Size().iHeight); |
|
1167 |
|
1168 iHeader->SetExtent( headerPosition, iHeader->Size() ); |
|
1169 bodyPosition.iY = iHeader->Rect().iBr.iY /* + 1 */; |
|
1170 iBody->SetExtent( bodyPosition, iBody->Size() ); |
|
1171 |
|
1172 MEBLOGGER_LEAVEFN( "CMsgEditorView::SizeChanged" ); |
|
1173 } |
|
1174 |
|
1175 // --------------------------------------------------------- |
|
1176 // CMsgEditorView::FocusChanged |
|
1177 // |
|
1178 // Sets focus off or on from focused control. This is called |
|
1179 // when e.g. options menu is shown. Removed e.g. cursor from |
|
1180 // text fields. |
|
1181 // --------------------------------------------------------- |
|
1182 // |
|
1183 void CMsgEditorView::FocusChanged( TDrawNow /*aDrawNow*/ ) |
|
1184 { |
|
1185 if ( iHeader && iBody ) |
|
1186 { |
|
1187 CMsgBaseControl* ctrl = FocusedControl(); |
|
1188 |
|
1189 if ( ctrl ) |
|
1190 { |
|
1191 if ( !( ctrl->IsNonFocusing() ) ) |
|
1192 { |
|
1193 ctrl->SetFocus( IsFocused(), IsFocused() ? EDrawNow: ENoDrawNow ); |
|
1194 } |
|
1195 } |
|
1196 |
|
1197 if ( IsFocused() ) |
|
1198 { |
|
1199 NotifyControlsForEvent( EMsgViewEventViewFocusGain, 0 ); |
|
1200 } |
|
1201 else |
|
1202 { |
|
1203 NotifyControlsForEvent( EMsgViewEventViewFocusLost, 0 ); |
|
1204 } |
|
1205 } |
|
1206 } |
|
1207 |
|
1208 // --------------------------------------------------------- |
|
1209 // CMsgEditorView::HandleResourceChange |
|
1210 // |
|
1211 // |
|
1212 // --------------------------------------------------------- |
|
1213 // |
|
1214 void CMsgEditorView::HandleResourceChange( TInt aType ) |
|
1215 { |
|
1216 // Updates child control layouts. Must be called before |
|
1217 // layout switch is handled here as AdjustComponentDistances |
|
1218 // expects controls to have correct height. Child control |
|
1219 // height may vary if layout is using different font. |
|
1220 CCoeControl::HandleResourceChange( aType ); |
|
1221 |
|
1222 if ( aType == KEikDynamicLayoutVariantSwitch ) |
|
1223 { |
|
1224 iScrollBar->SetScrollBarFrameObserver( this ); |
|
1225 |
|
1226 TInt invisibleLines( iFormOffset / iLineHeight ); |
|
1227 |
|
1228 iLineHeight = MsgEditorCommons::MsgBaseLineDelta(); |
|
1229 iBaseLineOffset = MsgEditorCommons::MsgBaseLineOffset(); |
|
1230 |
|
1231 // Correct the form offset to be multiple of current line height |
|
1232 iFormOffset = invisibleLines * iLineHeight; |
|
1233 |
|
1234 TRect mainPane = MsgEditorCommons::MsgMainPane(); |
|
1235 SetViewRect( mainPane ); |
|
1236 iSize = mainPane.Size(); |
|
1237 |
|
1238 AknLayoutUtils::LayoutVerticalScrollBar( |
|
1239 iScrollBar, |
|
1240 TRect( TPoint( 0, 0 ), mainPane.Size() ), |
|
1241 AknLayoutScalable_Apps::scroll_pane_cp017().LayoutLine() ); |
|
1242 |
|
1243 TRAP_IGNORE( RefreshViewL() ); |
|
1244 |
|
1245 EnsureCorrectViewPosition(); |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 // --------------------------------------------------------- |
|
1250 // CMsgEditorView::HandleControlEventL |
|
1251 // --------------------------------------------------------- |
|
1252 // |
|
1253 #ifdef RD_SCALABLE_UI_V2 |
|
1254 void CMsgEditorView::HandleControlEventL( CCoeControl* aControl, TCoeEvent aEventType ) |
|
1255 { |
|
1256 if ( aControl != iHeader && |
|
1257 aControl != iBody ) |
|
1258 { |
|
1259 switch( aEventType ) |
|
1260 { |
|
1261 case MCoeControlObserver::EEventPrepareFocusTransition: |
|
1262 { |
|
1263 // These things must be done before pointer event is handled. |
|
1264 CMsgBaseControl* baseControl = static_cast<CMsgBaseControl*>( aControl ); |
|
1265 |
|
1266 if ( baseControl && |
|
1267 ( baseControl->ControlType() == EMsgBodyControl || |
|
1268 baseControl->ControlType() == EMsgXhtmlBodyControl ) && |
|
1269 baseControl->ItemFinder() && |
|
1270 static_cast<CMsgBodyControl*>( baseControl )->Editor().TextView() ) |
|
1271 { |
|
1272 TInt componentIndex = iBody->ComponentIndexFromId( baseControl->ControlId() ); |
|
1273 baseControl->SetupAutomaticFindAfterFocusChangeL( iBody->CurrentFocus() <= componentIndex ); |
|
1274 } |
|
1275 |
|
1276 break; |
|
1277 } |
|
1278 case MCoeControlObserver::EEventRequestFocus: |
|
1279 { |
|
1280 // These things are done when pointer event is handled and focus should be changed. |
|
1281 // NOTE: CMsgAddressControlEditor is relying on focus not to set before |
|
1282 // pointer event is processed. Otherwise it is impossible to |
|
1283 // determine whether control has been focused before or not. |
|
1284 CMsgBaseControl* baseControl = static_cast<CMsgBaseControl*>( aControl ); |
|
1285 SetFocusByControlIdL( baseControl->ControlId(), ETrue, EFalse ); |
|
1286 |
|
1287 UpdateScrollBarL(); |
|
1288 } |
|
1289 default: |
|
1290 { |
|
1291 break; |
|
1292 } |
|
1293 } |
|
1294 } |
|
1295 //MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::HandleControlEventL")); |
|
1296 } |
|
1297 #else |
|
1298 void CMsgEditorView::HandleControlEventL( CCoeControl* /*aControl*/, TCoeEvent /*aEventType*/ ) |
|
1299 { |
|
1300 //MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::HandleControlEventL")); |
|
1301 } |
|
1302 #endif // RD_SCALABLE_UI_V2 |
|
1303 |
|
1304 // --------------------------------------------------------- |
|
1305 // CMsgEditorView::CreateHeaderL |
|
1306 // |
|
1307 // Creates the header. |
|
1308 // --------------------------------------------------------- |
|
1309 // |
|
1310 void CMsgEditorView::CreateHeaderL() |
|
1311 { |
|
1312 __ASSERT_DEBUG( iHeader == NULL, Panic( EMsgHeaderAlreadyExists ) ); |
|
1313 |
|
1314 TMargins margins; |
|
1315 |
|
1316 margins.iLeft = 0; |
|
1317 margins.iRight = 0; |
|
1318 margins.iTop = 0; |
|
1319 margins.iBottom = 0; |
|
1320 |
|
1321 iHeader = CMsgHeader::NewL( *this, margins ); |
|
1322 iHeader->SetObserver( this ); |
|
1323 } |
|
1324 |
|
1325 // --------------------------------------------------------- |
|
1326 // CMsgEditorView::CreateBodyL |
|
1327 // |
|
1328 // Creates the body. Creates also the default body control if requested. |
|
1329 // --------------------------------------------------------- |
|
1330 // |
|
1331 void CMsgEditorView::CreateBodyL() |
|
1332 { |
|
1333 __ASSERT_DEBUG( iBody == NULL, Panic( EMsgBodyAlreadyExists ) ); |
|
1334 |
|
1335 TMargins margins; |
|
1336 |
|
1337 margins.iLeft = 0; |
|
1338 margins.iRight = 0; |
|
1339 margins.iTop = 0; |
|
1340 margins.iBottom = 0; |
|
1341 |
|
1342 iBody = CMsgBody::NewL( *this, margins ); |
|
1343 iBody->SetObserver( this ); |
|
1344 |
|
1345 if ( !( iEditorModeFlags & EMsgDoNotUseDefaultBodyControl ) ) |
|
1346 { |
|
1347 CMsgBaseControl* bodyControl = CMsgBodyControl::NewL( this ); |
|
1348 bodyControl->SetControlType( EMsgBodyControl ); |
|
1349 DoAddControlL( bodyControl, EMsgComponentIdBody, EMsgFirstControl, EMsgBody ); |
|
1350 } |
|
1351 } |
|
1352 |
|
1353 // --------------------------------------------------------- |
|
1354 // CMsgEditorView::CreateScrollBarL |
|
1355 // |
|
1356 // Creates the scroll bar. |
|
1357 // --------------------------------------------------------- |
|
1358 // |
|
1359 void CMsgEditorView::CreateScrollBarL() |
|
1360 { |
|
1361 __ASSERT_DEBUG( iScrollBar == NULL, Panic( EMsgScrollBarAlreadyExists ) ); |
|
1362 |
|
1363 iScrollBar = new ( ELeave ) CEikScrollBarFrame( |
|
1364 this, // CCoeControl* aParentWindow |
|
1365 this // MEikScrollBarObserver* aObserver |
|
1366 ); |
|
1367 |
|
1368 // Check which type of scrollbar is to be shown |
|
1369 if ( AknLayoutUtils::DefaultScrollBarType( iAvkonAppUi ) == CEikScrollBarFrame::EDoubleSpan ) |
|
1370 { |
|
1371 // For EDoubleSpan type scrollbar |
|
1372 // non-window owning scrollbar |
|
1373 iScrollBar->CreateDoubleSpanScrollBarsL( EFalse, EFalse, ETrue, EFalse ); |
|
1374 iScrollBar->SetTypeOfVScrollBar( CEikScrollBarFrame::EDoubleSpan ); |
|
1375 |
|
1376 AknLayoutUtils::LayoutVerticalScrollBar( |
|
1377 iScrollBar, |
|
1378 TRect( TPoint( 0, 0 ), |
|
1379 MsgEditorCommons::MsgMainPane().Size() ), |
|
1380 AknLayoutScalable_Apps::scroll_pane_cp017().LayoutLine() ); |
|
1381 } |
|
1382 else |
|
1383 { |
|
1384 // For EArrowHead type scrollbar |
|
1385 iScrollBar->SetTypeOfVScrollBar( CEikScrollBarFrame::EArrowHead ); |
|
1386 } |
|
1387 |
|
1388 iScrollBar->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff, |
|
1389 CEikScrollBarFrame::EAuto ); |
|
1390 } |
|
1391 |
|
1392 // --------------------------------------------------------- |
|
1393 // CMsgEditorView::UpdateScrollBarL |
|
1394 // |
|
1395 // Updates the scroll bar. |
|
1396 // --------------------------------------------------------- |
|
1397 // |
|
1398 void CMsgEditorView::UpdateScrollBarL() |
|
1399 { |
|
1400 TInt height( 0 ); |
|
1401 TInt pos( 0 ); |
|
1402 TInt windowSize( iViewRect.Height() - iBaseLineOffset ); |
|
1403 |
|
1404 // Round height up to the next full line height. |
|
1405 MsgEditorCommons::RoundToNextLine( windowSize, iLineHeight ); |
|
1406 |
|
1407 GetVirtualFormHeightAndPos( height, pos ); |
|
1408 |
|
1409 // Round height up to the next full line height. |
|
1410 MsgEditorCommons::RoundToNextLine( height, iLineHeight ); |
|
1411 |
|
1412 if ( pos < iLineHeight ) |
|
1413 { |
|
1414 pos = 0; |
|
1415 } |
|
1416 |
|
1417 // Round position up to the next full line height. |
|
1418 MsgEditorCommons::RoundToNextLine( pos, iLineHeight ); |
|
1419 |
|
1420 #ifdef _DEBUG |
|
1421 // CAknScrollIndicator::SetPosition has an __ASSERT_DEBUG |
|
1422 // for range check even if the control handles out-of-range |
|
1423 // values properly. |
|
1424 if ( pos > height ) pos = height; |
|
1425 if ( pos < -1 ) pos = -1; |
|
1426 |
|
1427 #endif |
|
1428 |
|
1429 if ( iScrollBar->TypeOfVScrollBar() == CEikScrollBarFrame::EDoubleSpan ) |
|
1430 { |
|
1431 TAknDoubleSpanScrollBarModel vDsSbarModel; |
|
1432 vDsSbarModel.SetScrollSpan( height ); |
|
1433 vDsSbarModel.SetWindowSize( windowSize ); |
|
1434 |
|
1435 pos = Max( 0, Min( height - windowSize, pos ) ); |
|
1436 |
|
1437 vDsSbarModel.SetFocusPosition( pos ); |
|
1438 |
|
1439 TEikScrollBarFrameLayout layout; |
|
1440 layout.iTilingMode = TEikScrollBarFrameLayout::EInclusiveRectConstant; |
|
1441 |
|
1442 // It seems to be important that we have separate |
|
1443 // variable for "inclusiveRect" and "clientRect" |
|
1444 TRect inclusiveRect( Rect() ); |
|
1445 TRect clientRect( Rect() ); |
|
1446 |
|
1447 iScrollBar->TileL( NULL, &vDsSbarModel, clientRect, inclusiveRect, layout ); |
|
1448 iScrollBar->SetVFocusPosToThumbPos( vDsSbarModel.FocusPosition() ); |
|
1449 |
|
1450 iViewFocusPosition = vDsSbarModel.FocusPosition(); |
|
1451 } |
|
1452 else |
|
1453 { |
|
1454 TEikScrollBarModel vertModel; |
|
1455 vertModel.iScrollSpan = height; |
|
1456 vertModel.iThumbSpan = windowSize; |
|
1457 vertModel.iThumbPosition = pos; |
|
1458 |
|
1459 TEikScrollBarFrameLayout layout; |
|
1460 |
|
1461 TRect rect( Rect() ); |
|
1462 iScrollBar->TileL( NULL, &vertModel, rect, rect, layout ); |
|
1463 iScrollBar->SetVFocusPosToThumbPos( vertModel.iThumbPosition ); |
|
1464 |
|
1465 iViewFocusPosition = vertModel.iThumbPosition; |
|
1466 } |
|
1467 |
|
1468 MsgEditorCommons::RoundToNextLine( iViewFocusPosition, iLineHeight ); |
|
1469 } |
|
1470 |
|
1471 |
|
1472 // --------------------------------------------------------- |
|
1473 // CMsgEditorView::GetVirtualFormHeightAndPos |
|
1474 // |
|
1475 // Return virtual height and virtual Y position of the form. |
|
1476 // This function assumes that only body can contain controls which virtual |
|
1477 // height must be calculated. Also this funtion assumes that only the |
|
1478 // currently focused control in the body can contain text above visible |
|
1479 // text view. |
|
1480 // --------------------------------------------------------- |
|
1481 // |
|
1482 void CMsgEditorView::GetVirtualFormHeightAndPos( TInt& aHeight, TInt& aPos ) |
|
1483 { |
|
1484 TInt screenHeight = MsgEditorCommons::EditorViewHeigth() - iBaseLineOffset; |
|
1485 |
|
1486 TInt scrollPartsHeight( 0 ); |
|
1487 TInt abovePartHeight( 0 ); |
|
1488 |
|
1489 TInt bodyHeight( iBody->VirtualHeight() ); |
|
1490 |
|
1491 TInt headerHeight( 0 ); |
|
1492 |
|
1493 TBool headerLoaded( iHeader->CountMsgControls() ); |
|
1494 if ( headerLoaded ) |
|
1495 { |
|
1496 // Header loaded so get header height and subtract base line offset |
|
1497 // from it as header first control contains it and it is not scrollable |
|
1498 // area. |
|
1499 headerHeight = iHeader->VirtualHeight() - iBaseLineOffset; |
|
1500 } |
|
1501 else |
|
1502 { |
|
1503 // No header so baseline offset is added to the first body control's distance. |
|
1504 // Baseline offset is not scrollable area so it must be subtracted from body height. |
|
1505 bodyHeight -= iBaseLineOffset; |
|
1506 } |
|
1507 |
|
1508 iVisiblePartHeight = bodyHeight + headerHeight; |
|
1509 |
|
1510 // Visible height is always at least one screen height. |
|
1511 iVisiblePartHeight = Max( screenHeight, iVisiblePartHeight ); |
|
1512 |
|
1513 // Calculate total scroll parts high excluding visible part and |
|
1514 // height of the scroll parts above visible part. |
|
1515 TInt singlePartHeight = Max( screenHeight, iVisiblePartHeight / 10 ); |
|
1516 for ( TInt current = 0; current < iScrollParts; current++ ) |
|
1517 { |
|
1518 if ( current != iVisiblePart ) |
|
1519 { |
|
1520 scrollPartsHeight += singlePartHeight; |
|
1521 |
|
1522 if ( current < iVisiblePart ) |
|
1523 { |
|
1524 abovePartHeight = scrollPartsHeight; |
|
1525 } |
|
1526 } |
|
1527 } |
|
1528 |
|
1529 aHeight = iVisiblePartHeight + scrollPartsHeight; |
|
1530 |
|
1531 if ( iCurrentFocus == EMsgBodyFocused ) |
|
1532 { |
|
1533 TInt bodyExt = abovePartHeight + iBody->VirtualExtension(); |
|
1534 |
|
1535 if ( headerLoaded ) |
|
1536 { |
|
1537 // Remove visible header pixels from header height. |
|
1538 TInt visiblePixels( iHeader->Position().iY + iHeader->Size().iHeight - iBaseLineOffset ); |
|
1539 if ( visiblePixels > 0 ) |
|
1540 { |
|
1541 headerHeight -= visiblePixels; |
|
1542 } |
|
1543 } |
|
1544 else |
|
1545 { |
|
1546 // No header so baseline offset is added to the first body control's distance. |
|
1547 // Baseline offset is not scrollable area so it must be subtracted from body extension. |
|
1548 bodyExt -= iBaseLineOffset; |
|
1549 } |
|
1550 |
|
1551 aPos = headerHeight + bodyExt; |
|
1552 |
|
1553 if ( iVisiblePart == ( iScrollParts - 1 ) ) |
|
1554 { |
|
1555 // This ensures that if we at the end of the scroll area then scroll position is also |
|
1556 // at the end. |
|
1557 CMsgBaseControl* ctrl = FocusedControl(); |
|
1558 |
|
1559 if ( ctrl && |
|
1560 ctrl->IsCursorLocation( EMsgBottom ) && |
|
1561 NextFocusableFormControl( iBody, |
|
1562 iBody->CurrentFocus() + 1, |
|
1563 EMsgFocusDown ) == KErrNotFound ) |
|
1564 { |
|
1565 // Further scrolling (down) not possible. |
|
1566 aPos = aHeight; |
|
1567 |
|
1568 if ( iScrollBar->TypeOfVScrollBar() == CEikScrollBarFrame::EDoubleSpan ) |
|
1569 { |
|
1570 // Focus position is top of the view. |
|
1571 aPos -= screenHeight; |
|
1572 } |
|
1573 } |
|
1574 } |
|
1575 } |
|
1576 else |
|
1577 { |
|
1578 aPos = abovePartHeight + iHeader->VirtualExtension() - iBaseLineOffset; |
|
1579 } |
|
1580 } |
|
1581 |
|
1582 // --------------------------------------------------------- |
|
1583 // CMsgEditorView::SetAndGetSizeL |
|
1584 // |
|
1585 // Sets sizes for the header and the body and returns their total size aSize |
|
1586 // as a reference. The function does not set new sizes for the controls if |
|
1587 // the aInit argument is EFalse. If aInit == ETrue, this function sets the size |
|
1588 // so that only a total height can change. |
|
1589 // --------------------------------------------------------- |
|
1590 // |
|
1591 void CMsgEditorView::SetAndGetSizeL( TSize& aSize, TBool aInit ) |
|
1592 { |
|
1593 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1594 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1595 |
|
1596 if ( aInit && iStateFlags & EMsgStateInitialized ) |
|
1597 { |
|
1598 // Size changing at run time. Set intializing flag on. |
|
1599 iStateFlags |= EMsgStateInitializing; |
|
1600 } |
|
1601 |
|
1602 TSize editorSize( aSize ); |
|
1603 TSize headerSize( 0, 0 ); |
|
1604 TSize bodySize( 0, 0 ); |
|
1605 |
|
1606 headerSize = aSize; |
|
1607 iHeader->SetAndGetSizeL( headerSize, aInit ); |
|
1608 |
|
1609 bodySize = aSize; |
|
1610 iBody->SetAndGetSizeL( bodySize, aInit ); |
|
1611 |
|
1612 editorSize.iHeight = headerSize.iHeight + bodySize.iHeight; |
|
1613 |
|
1614 // View size must always be the size of client rect. Don't change "iSize"! |
|
1615 aSize = editorSize; |
|
1616 |
|
1617 if ( aInit && iStateFlags & EMsgStateInitialized ) |
|
1618 { |
|
1619 iStateFlags &= ~EMsgStateInitializing; |
|
1620 } |
|
1621 } |
|
1622 |
|
1623 // --------------------------------------------------------- |
|
1624 // CMsgEditorView::RefreshViewL |
|
1625 // |
|
1626 // Sets the positions for the controls and re-draws the view. |
|
1627 // --------------------------------------------------------- |
|
1628 // |
|
1629 void CMsgEditorView::RefreshViewL() |
|
1630 { |
|
1631 iStateFlags |= EMsgStateRefreshing; |
|
1632 |
|
1633 // Component must know their correct height by now. |
|
1634 AdjustComponentDistances(); |
|
1635 |
|
1636 TSize editorSize( iViewRect.Size() ); |
|
1637 |
|
1638 // Called after AdjustComponentDistances because that |
|
1639 // information is used on some components to calculate |
|
1640 // their sizes |
|
1641 SetAndGetSizeL( editorSize, ETrue ); |
|
1642 SizeChanged(); |
|
1643 |
|
1644 UpdateScrollBarL(); |
|
1645 |
|
1646 NotifyControlsForEvent( EMsgViewEventPrepareForViewing, 0 ); |
|
1647 DrawDeferred(); |
|
1648 |
|
1649 iStateFlags &= ~EMsgStateRefreshing; |
|
1650 |
|
1651 EnsureCorrectFormPosition( EFalse ); |
|
1652 } |
|
1653 |
|
1654 // --------------------------------------------------------- |
|
1655 // CMsgEditorView::NotifyControlsForEvent |
|
1656 // |
|
1657 // Notifies controls for an event. |
|
1658 // --------------------------------------------------------- |
|
1659 // |
|
1660 void CMsgEditorView::NotifyControlsForEvent( TMsgViewEvent aEvent, TInt aParam ) |
|
1661 { |
|
1662 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1663 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1664 |
|
1665 iHeader->NotifyControlsForEvent( aEvent, aParam ); |
|
1666 iBody->NotifyControlsForEvent( aEvent, aParam ); |
|
1667 } |
|
1668 |
|
1669 // --------------------------------------------------------- |
|
1670 // CMsgEditorView::SetFocusByControlIdL |
|
1671 // |
|
1672 // Sets focus to a control aControlId. aSetCursorPos specified |
|
1673 // whether cursor position should be set or not. |
|
1674 // --------------------------------------------------------- |
|
1675 // |
|
1676 void CMsgEditorView::SetFocusByControlIdL( TInt aControlId, |
|
1677 TBool aCorrectFormPosition, |
|
1678 TBool aSetCursorPos ) |
|
1679 { |
|
1680 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1681 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1682 __ASSERT_DEBUG( aControlId >= 0, Panic( EMsgIncorrectControlId ) ); |
|
1683 |
|
1684 NotifyControlsForEvent( EMsgViewEventFocusMoveStarting, 0 ); |
|
1685 |
|
1686 ReportFocusMovement( MMsgEditorObserver::EMsgFocusMovingFrom ); |
|
1687 |
|
1688 TInt componentIndex = iHeader->ComponentIndexFromId( aControlId ); |
|
1689 |
|
1690 if ( componentIndex != KErrNotFound ) |
|
1691 { |
|
1692 // Control where focus is wanted to be moved was found from header. |
|
1693 if ( iCurrentFocus == EMsgBodyFocused ) |
|
1694 { |
|
1695 if (IsReadOnly()) // viewer |
|
1696 { |
|
1697 iBody->NotifyControlsForEvent( EMsgViewEventPrepareFocusTransitionUp, 0 ); |
|
1698 iBody->SetFocus( EFalse, |
|
1699 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1700 ENoDrawNow ); |
|
1701 } |
|
1702 else |
|
1703 { |
|
1704 iBody->SetFocus( EFalse, |
|
1705 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1706 ENoDrawNow ); |
|
1707 iBody->NotifyControlsForEvent( EMsgViewEventPrepareFocusTransitionUp, 0 ); |
|
1708 } |
|
1709 } |
|
1710 |
|
1711 TMsgFocus previousMsgPart = iCurrentFocus; |
|
1712 iCurrentFocus = EMsgHeaderFocused; |
|
1713 |
|
1714 TInt delta = componentIndex - iHeader->CurrentFocus(); |
|
1715 |
|
1716 if ( delta != 0 ) |
|
1717 { |
|
1718 iHeader->SetFocus( EFalse, |
|
1719 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1720 ENoDrawNow ); |
|
1721 iHeader->NotifyControlsForEvent( delta > 0 ? EMsgViewEventPrepareFocusTransitionDown : |
|
1722 EMsgViewEventPrepareFocusTransitionUp, |
|
1723 0 ); |
|
1724 } |
|
1725 |
|
1726 // Do real focus movement when focus is moved between |
|
1727 // message parts or when focus is moved inside message part |
|
1728 // to different component. Do it also if currently focused |
|
1729 // control does not have focus really. |
|
1730 if ( componentIndex != iHeader->CurrentFocus() || |
|
1731 previousMsgPart != iCurrentFocus || |
|
1732 !iHeader->FocusedControl()->IsFocused() ) |
|
1733 { |
|
1734 if ( !iHeader->ChangeFocusTo( componentIndex, |
|
1735 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1736 ENoDrawNow ) ) |
|
1737 { |
|
1738 __ASSERT_DEBUG( EFalse, Panic( EMsgNonFocusingControl ) ); |
|
1739 } |
|
1740 } |
|
1741 } |
|
1742 else |
|
1743 { |
|
1744 componentIndex = iBody->ComponentIndexFromId( aControlId ); |
|
1745 |
|
1746 if ( componentIndex != KErrNotFound ) |
|
1747 { |
|
1748 // Control where focus is wanted to be moved was found from body. |
|
1749 if ( iCurrentFocus == EMsgHeaderFocused ) |
|
1750 { |
|
1751 if (IsReadOnly()) |
|
1752 { |
|
1753 iHeader->NotifyControlsForEvent( EMsgViewEventPrepareFocusTransitionDown, 0 ); |
|
1754 iHeader->SetFocus( EFalse, |
|
1755 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1756 ENoDrawNow ); |
|
1757 } |
|
1758 else |
|
1759 { |
|
1760 |
|
1761 iHeader->SetFocus( EFalse, |
|
1762 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1763 ENoDrawNow ); |
|
1764 iHeader->NotifyControlsForEvent( EMsgViewEventPrepareFocusTransitionDown, 0 ); |
|
1765 } |
|
1766 } |
|
1767 TMsgFocus previousMsgPart = iCurrentFocus; |
|
1768 iCurrentFocus = EMsgBodyFocused; |
|
1769 |
|
1770 TInt delta = componentIndex - iBody->CurrentFocus(); |
|
1771 |
|
1772 if ( delta != 0 ) |
|
1773 { |
|
1774 iBody->SetFocus( EFalse, |
|
1775 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1776 ENoDrawNow ); |
|
1777 iBody->NotifyControlsForEvent( delta ? EMsgViewEventPrepareFocusTransitionDown : |
|
1778 EMsgViewEventPrepareFocusTransitionUp, |
|
1779 0 ); |
|
1780 } |
|
1781 |
|
1782 // Do real focus movement when focus is moved between |
|
1783 // message parts or when focus is moved inside message part |
|
1784 // to different component. Do it also if currently focused |
|
1785 // control does not have focus really. |
|
1786 if ( componentIndex != iBody->CurrentFocus() || |
|
1787 previousMsgPart != iCurrentFocus || |
|
1788 !iBody->FocusedControl()->IsFocused() ) |
|
1789 { |
|
1790 CMsgBaseControl* ctrl = iBody->MsgControl( componentIndex ); |
|
1791 |
|
1792 if ( aSetCursorPos && |
|
1793 ctrl && |
|
1794 ( ctrl->ControlType() == EMsgBodyControl || |
|
1795 ctrl->ControlType() == EMsgXhtmlBodyControl ) && |
|
1796 ctrl->ItemFinder() && |
|
1797 static_cast<CMsgBodyControl*>( ctrl )->Editor().TextView() ) |
|
1798 { |
|
1799 ctrl->SetupAutomaticFindAfterFocusChangeL( iBody->CurrentFocus() <= componentIndex ); |
|
1800 } |
|
1801 |
|
1802 if ( !iBody->ChangeFocusTo( componentIndex, |
|
1803 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
1804 ENoDrawNow ) ) |
|
1805 { |
|
1806 __ASSERT_DEBUG( EFalse, Panic( EMsgNonFocusingControl ) ); |
|
1807 } |
|
1808 } |
|
1809 } |
|
1810 else |
|
1811 { |
|
1812 __ASSERT_DEBUG( EFalse, Panic( EMsgNoFocusingControlExist ) ); |
|
1813 } |
|
1814 } |
|
1815 |
|
1816 NotifyControlsForEvent( EMsgViewEventFocusMoveFinished, 0 ); |
|
1817 |
|
1818 ReportFocusMovement( MMsgEditorObserver::EMsgFocusMovedTo ); |
|
1819 |
|
1820 if ( aCorrectFormPosition ) |
|
1821 { |
|
1822 EnsureCorrectFormPosition( IsReadOnly() ); |
|
1823 } |
|
1824 |
|
1825 if ( aSetCursorPos && |
|
1826 IsReadOnly() && |
|
1827 FocusedControl() ) |
|
1828 { |
|
1829 FocusedControl()->NotifyViewEvent( EMsgViewEventSetCursorLastPos, 0 ); |
|
1830 } |
|
1831 } |
|
1832 |
|
1833 // --------------------------------------------------------- |
|
1834 // CMsgEditorView::DoAddControlL |
|
1835 // |
|
1836 // Does an actual add operation for the control by setting all the necessary |
|
1837 // observers etc. |
|
1838 // --------------------------------------------------------- |
|
1839 // |
|
1840 void CMsgEditorView::DoAddControlL( CMsgBaseControl* aControl, |
|
1841 TInt aControlId, |
|
1842 TInt aIndex, |
|
1843 TMsgFormComponent aFormComponent ) |
|
1844 { |
|
1845 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1846 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1847 |
|
1848 // set readonly for control here because readonly flag |
|
1849 // may be needed before ActivateL call. |
|
1850 TUint32 flags = aControl->ControlModeFlags(); |
|
1851 if ( IsReadOnly() || |
|
1852 flags & EMsgControlModeReadOnly ) |
|
1853 { |
|
1854 flags |= EMsgControlModeReadOnly; |
|
1855 } |
|
1856 else |
|
1857 { |
|
1858 flags &= ~EMsgControlModeReadOnly; |
|
1859 } |
|
1860 aControl->SetControlModeFlags( flags ); |
|
1861 |
|
1862 if ( !aControl->OwnsWindow() ) |
|
1863 { |
|
1864 aControl->SetContainerWindowL( *this ); |
|
1865 } |
|
1866 |
|
1867 aControl->SetObserver( this ); |
|
1868 aControl->SetBaseControlObserver( *this ); |
|
1869 |
|
1870 if ( iEdwinObserver ) |
|
1871 { |
|
1872 CEikRichTextEditor* editor = NULL; |
|
1873 |
|
1874 if ( aControl->ControlType() == EMsgExpandableControl || |
|
1875 aControl->ControlType() == EMsgAddressControl ) |
|
1876 { |
|
1877 editor = &static_cast<CMsgExpandableControl*>( aControl )->Editor(); |
|
1878 } |
|
1879 else if ( aControl->ControlType() == EMsgBodyControl || |
|
1880 aControl->ControlType() == EMsgXhtmlBodyControl ) |
|
1881 { |
|
1882 editor = &static_cast<CMsgBodyControl*>( aControl )->Editor(); |
|
1883 } |
|
1884 |
|
1885 if ( editor ) |
|
1886 { |
|
1887 editor->AddEdwinObserverL( iEdwinObserver ); |
|
1888 } |
|
1889 } |
|
1890 |
|
1891 aControl->MakeVisible( ETrue ); |
|
1892 aControl->ActivateL(); |
|
1893 |
|
1894 // this calls PrepareForReadOnly and sets flags again |
|
1895 // but it doesn't matter. |
|
1896 aControl->SetReadOnly( flags & EMsgControlModeReadOnly ); |
|
1897 |
|
1898 if ( aFormComponent == EMsgHeader ) |
|
1899 { |
|
1900 iHeader->AddControlL( aControl, aControlId, aIndex ); |
|
1901 } |
|
1902 else if ( aFormComponent == EMsgBody ) |
|
1903 { |
|
1904 iBody->AddControlL( aControl, aControlId, aIndex ); |
|
1905 |
|
1906 if ( iHeader->CountMsgControls() == 0 ) |
|
1907 { |
|
1908 iCurrentFocus = EMsgBodyFocused; |
|
1909 } |
|
1910 } |
|
1911 else |
|
1912 { |
|
1913 __ASSERT_DEBUG( EFalse, Panic( EMsgIncorrectFormComponent ) ); |
|
1914 } |
|
1915 |
|
1916 if ( aControl->UniqueHandle() == KErrNotFound ) |
|
1917 { |
|
1918 // Control added first time. Set unique handle. |
|
1919 aControl->SetUniqueHandle( iUniqueHandlePool ); |
|
1920 iUniqueHandlePool++; |
|
1921 } |
|
1922 |
|
1923 if ( iStateFlags & EMsgStateInitialized ) // Control is added on run-time. |
|
1924 { |
|
1925 TRAPD( err, RefreshViewL() ); |
|
1926 |
|
1927 if ( err != KErrNone ) |
|
1928 { |
|
1929 // if RefreshViewL fails, remove the added control from internal |
|
1930 // structures, i.e. transfer ownership back to caller. |
|
1931 if ( aFormComponent == EMsgHeader ) |
|
1932 { |
|
1933 iHeader->RemoveControlL( aControlId ); // does not leave. |
|
1934 } |
|
1935 else if ( aFormComponent == EMsgBody ) |
|
1936 { |
|
1937 iBody->RemoveControlL( aControlId ); // does not leave. |
|
1938 } |
|
1939 |
|
1940 User::Leave( err ); |
|
1941 } |
|
1942 else |
|
1943 { |
|
1944 // Set control initialized as it has been successfully added & activated. |
|
1945 flags = aControl->ControlModeFlags(); |
|
1946 flags |= EMsgControlModeInitialized; |
|
1947 aControl->SetControlModeFlags( flags ); |
|
1948 } |
|
1949 } |
|
1950 } |
|
1951 |
|
1952 // --------------------------------------------------------- |
|
1953 // CMsgEditorView::RotateFocusL |
|
1954 // |
|
1955 // Rotates focus up or down depending aDirection argument. Returns ETrue if |
|
1956 // operation can be done. |
|
1957 // --------------------------------------------------------- |
|
1958 // |
|
1959 TBool CMsgEditorView::RotateFocusL( TMsgFocusDirection aDirection, |
|
1960 MMsgEditorObserver::TMsgFocusEvent& aFocusEvent ) |
|
1961 { |
|
1962 __ASSERT_DEBUG( iHeader != NULL, Panic( EMsgHeaderNotExists ) ); |
|
1963 __ASSERT_DEBUG( iBody != NULL, Panic( EMsgBodyNotExists ) ); |
|
1964 |
|
1965 TBool startAutoFind = EFalse; |
|
1966 TBool setMaxHeight = EFalse; |
|
1967 |
|
1968 TInt newFocus = KErrNotFound; |
|
1969 TInt controlIndex = 0; |
|
1970 |
|
1971 CMsgFormComponent* currForm = NULL; |
|
1972 CMsgFormComponent* nextForm = NULL; |
|
1973 |
|
1974 if ( iCurrentFocus == EMsgHeaderFocused ) |
|
1975 { |
|
1976 currForm = iHeader; |
|
1977 controlIndex = iHeader->CurrentFocus(); |
|
1978 |
|
1979 if ( aDirection == EMsgFocusDown ) |
|
1980 { |
|
1981 newFocus = NextFocusableFormControl( iHeader, controlIndex + 1, EMsgFocusDown ); |
|
1982 |
|
1983 if ( newFocus != KErrNotFound ) |
|
1984 { |
|
1985 nextForm = iHeader; |
|
1986 } |
|
1987 else |
|
1988 { |
|
1989 newFocus = NextFocusableFormControl( iBody, 0, EMsgFocusDown ); |
|
1990 |
|
1991 if ( newFocus != KErrNotFound ) |
|
1992 { |
|
1993 startAutoFind = ETrue; |
|
1994 nextForm = iBody; |
|
1995 aFocusEvent = MMsgEditorObserver::EMsgFocusToBody; |
|
1996 } |
|
1997 else |
|
1998 { |
|
1999 TInt currentlyFocused = iBody->CurrentFocus(); |
|
2000 |
|
2001 if ( IsFocusable( iBody->MsgControl( currentlyFocused ), EMsgFocusDown ) ) |
|
2002 { |
|
2003 // Refocus the currently focused control. |
|
2004 nextForm = iBody; |
|
2005 startAutoFind = ETrue; |
|
2006 newFocus = currentlyFocused; |
|
2007 } |
|
2008 |
|
2009 aFocusEvent = MMsgEditorObserver::EMsgFocusAtBottom; |
|
2010 } |
|
2011 } |
|
2012 } |
|
2013 else if ( aDirection == EMsgFocusUp ) |
|
2014 { |
|
2015 newFocus = NextFocusableFormControl( iHeader, controlIndex - 1, EMsgFocusUp ); |
|
2016 |
|
2017 if ( newFocus != KErrNotFound ) |
|
2018 { |
|
2019 nextForm = iHeader; |
|
2020 } |
|
2021 else |
|
2022 { |
|
2023 aFocusEvent = MMsgEditorObserver::EMsgFocusAtTop; |
|
2024 } |
|
2025 } |
|
2026 } |
|
2027 else if ( iCurrentFocus == EMsgBodyFocused ) |
|
2028 { |
|
2029 currForm = iBody; |
|
2030 controlIndex = iBody->CurrentFocus(); |
|
2031 |
|
2032 if ( aDirection == EMsgFocusDown ) |
|
2033 { |
|
2034 newFocus = NextFocusableFormControl( iBody, controlIndex + 1, EMsgFocusDown ); |
|
2035 |
|
2036 if ( newFocus != KErrNotFound ) |
|
2037 { |
|
2038 nextForm = iBody; |
|
2039 } |
|
2040 else |
|
2041 { |
|
2042 aFocusEvent = MMsgEditorObserver::EMsgFocusAtBottom; |
|
2043 } |
|
2044 } |
|
2045 else if ( aDirection == EMsgFocusUp ) |
|
2046 { |
|
2047 newFocus = NextFocusableFormControl( iBody, controlIndex - 1, EMsgFocusUp ); |
|
2048 |
|
2049 if ( newFocus != KErrNotFound ) |
|
2050 { |
|
2051 nextForm = iBody; |
|
2052 } |
|
2053 else |
|
2054 { |
|
2055 newFocus = NextFocusableFormControl( iHeader, iHeader->CountMsgControls() - 1, EMsgFocusUp ); |
|
2056 setMaxHeight = ETrue; |
|
2057 |
|
2058 if ( newFocus != KErrNotFound ) |
|
2059 { |
|
2060 nextForm = iHeader; |
|
2061 aFocusEvent = MMsgEditorObserver::EMsgFocusToHeader; |
|
2062 } |
|
2063 else |
|
2064 { |
|
2065 TInt currentlyFocused = iHeader->CurrentFocus(); |
|
2066 if ( IsFocusable( iHeader->MsgControl( currentlyFocused ), EMsgFocusUp ) ) |
|
2067 { |
|
2068 // Refocus the currently focused control. |
|
2069 nextForm = iHeader; |
|
2070 newFocus = currentlyFocused; |
|
2071 } |
|
2072 |
|
2073 aFocusEvent = MMsgEditorObserver::EMsgFocusAtTop; |
|
2074 } |
|
2075 } |
|
2076 } |
|
2077 |
|
2078 if ( ( aFocusEvent == MMsgEditorObserver::EMsgFocusNone || |
|
2079 aFocusEvent == MMsgEditorObserver::EMsgFocusToBody ) && |
|
2080 ( newFocus != controlIndex && |
|
2081 newFocus > KErrNotFound ) ) // for automatic highlight |
|
2082 { |
|
2083 // we assume that editor size is correct in this point |
|
2084 startAutoFind = ETrue; |
|
2085 } |
|
2086 |
|
2087 } |
|
2088 |
|
2089 if ( setMaxHeight ) |
|
2090 { |
|
2091 CMsgBaseControl* ctrl = FocusedControl(); // for automatic highlight |
|
2092 |
|
2093 if ( ctrl && |
|
2094 ( ctrl->ControlType() == EMsgBodyControl || |
|
2095 ctrl->ControlType() == EMsgXhtmlBodyControl ) && |
|
2096 ctrl->ItemFinder() ) |
|
2097 { |
|
2098 static_cast<CMsgBodyControl*>( ctrl )->Editor().SetMaximumHeight( |
|
2099 MsgEditorCommons::MaxBodyHeight() ); |
|
2100 } // for automatic highlight |
|
2101 } |
|
2102 |
|
2103 if ( nextForm != NULL ) |
|
2104 { |
|
2105 NotifyControlsForEvent( aDirection == EMsgFocusUp ? EMsgViewEventPrepareFocusTransitionUp : |
|
2106 EMsgViewEventPrepareFocusTransitionDown, |
|
2107 0 ); |
|
2108 |
|
2109 NotifyControlsForEvent( EMsgViewEventFocusMoveStarting, 0 ); |
|
2110 |
|
2111 ReportFocusMovement( MMsgEditorObserver::EMsgFocusMovingFrom ); |
|
2112 |
|
2113 if ( nextForm == currForm ) |
|
2114 { |
|
2115 currForm->ChangeFocusTo( newFocus, |
|
2116 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
2117 ENoDrawNow ); |
|
2118 } |
|
2119 else |
|
2120 { |
|
2121 currForm->SetFocus( EFalse, |
|
2122 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
2123 ENoDrawNow ); |
|
2124 iCurrentFocus = ( nextForm == iBody ) ? EMsgBodyFocused : |
|
2125 EMsgHeaderFocused; |
|
2126 |
|
2127 nextForm->ChangeFocusTo( newFocus, |
|
2128 iStateFlags & EMsgStateInitialized ? EDrawNow : |
|
2129 ENoDrawNow ); |
|
2130 } |
|
2131 |
|
2132 CMsgBaseControl* focusedControl = FocusedControl(); |
|
2133 |
|
2134 if ( focusedControl ) |
|
2135 { |
|
2136 if ( aDirection == EMsgFocusDown ) |
|
2137 { |
|
2138 focusedControl->NotifyViewEvent( EMsgViewEventSetCursorFirstPos, 0 ); |
|
2139 } |
|
2140 else if ( aDirection == EMsgFocusUp ) |
|
2141 { |
|
2142 focusedControl->NotifyViewEvent( EMsgViewEventSetCursorLastPos, 0 ); |
|
2143 } |
|
2144 } |
|
2145 |
|
2146 NotifyControlsForEvent( EMsgViewEventFocusMoveFinished, 0 ); |
|
2147 |
|
2148 ReportFocusMovement( MMsgEditorObserver::EMsgFocusMovedTo ); |
|
2149 } |
|
2150 else |
|
2151 { |
|
2152 CMsgBaseControl* focusedControl = FocusedControl(); |
|
2153 |
|
2154 if ( !IsReadOnly() && focusedControl && !startAutoFind ) |
|
2155 { |
|
2156 // Focus is tried to move to direction that does not cause any focus |
|
2157 // changes (either up when already at the topmost position or down when |
|
2158 // already at the bottommost position) on editor. |
|
2159 // => Set focused cursor position to either last or first position if we |
|
2160 // are at last or first scroll part. |
|
2161 if ( aDirection == EMsgFocusDown && |
|
2162 iVisiblePart == iScrollParts - 1 ) |
|
2163 { |
|
2164 if ( focusedControl->ControlType() == EMsgBodyControl || |
|
2165 focusedControl->ControlType() == EMsgXhtmlBodyControl ) |
|
2166 { |
|
2167 CEikRichTextEditor& editor = static_cast<CMsgBodyControl*>( focusedControl )->Editor(); |
|
2168 editor.SetCursorPosL( editor.TextLength(), EFalse ); |
|
2169 } |
|
2170 else if ( focusedControl->ControlType() == EMsgExpandableControl || |
|
2171 focusedControl->ControlType() == EMsgAddressControl ) |
|
2172 { |
|
2173 CEikRichTextEditor& editor = |
|
2174 static_cast<CMsgExpandableControl*>( focusedControl )->Editor(); |
|
2175 editor.SetCursorPosL( editor.TextLength(), EFalse ); |
|
2176 |
|
2177 if ( focusedControl->ControlType() == EMsgAddressControl ) |
|
2178 { |
|
2179 // Update the address field highlighting |
|
2180 static_cast<CMsgAddressControlEditor&>( editor ).CheckHighlightingL(); |
|
2181 } |
|
2182 } |
|
2183 } |
|
2184 else if ( aDirection == EMsgFocusUp && |
|
2185 iVisiblePart == 0) |
|
2186 { |
|
2187 if ( focusedControl->ControlType() == EMsgBodyControl || |
|
2188 focusedControl->ControlType() == EMsgXhtmlBodyControl ) |
|
2189 { |
|
2190 CEikRichTextEditor& editor = static_cast<CMsgBodyControl*>( focusedControl )->Editor(); |
|
2191 editor.SetCursorPosL( 0, EFalse ); |
|
2192 } |
|
2193 else if ( focusedControl->ControlType() == EMsgExpandableControl || |
|
2194 focusedControl->ControlType() == EMsgAddressControl ) |
|
2195 { |
|
2196 CEikRichTextEditor& editor = |
|
2197 static_cast<CMsgExpandableControl*>( focusedControl )->Editor(); |
|
2198 editor.SetCursorPosL( 0, EFalse ); |
|
2199 |
|
2200 if ( focusedControl->ControlType() == EMsgAddressControl ) |
|
2201 { |
|
2202 // Update the address field highlighting |
|
2203 static_cast<CMsgAddressControlEditor&>( editor ).CheckHighlightingL(); |
|
2204 } |
|
2205 } |
|
2206 } |
|
2207 } |
|
2208 } |
|
2209 |
|
2210 if ( startAutoFind ) |
|
2211 { |
|
2212 CMsgBaseControl* ctrl = (CMsgBaseControl*)iBody->MsgControl( newFocus ); |
|
2213 |
|
2214 if ( ctrl && |
|
2215 ( ctrl->ControlType() == EMsgBodyControl || |
|
2216 ctrl->ControlType() == EMsgXhtmlBodyControl ) && |
|
2217 ctrl->ItemFinder() && |
|
2218 static_cast<CMsgBodyControl*>( ctrl )->Editor().TextView() ) |
|
2219 { |
|
2220 ctrl->SetupAutomaticFindAfterFocusChangeL( aDirection == EMsgFocusDown ); |
|
2221 } |
|
2222 } |
|
2223 |
|
2224 return newFocus != KErrNotFound; |
|
2225 } |
|
2226 |
|
2227 // --------------------------------------------------------- |
|
2228 // CMsgEditorView::EnsureCorrectFormPosition |
|
2229 // |
|
2230 // Ensures that the cursor is visible on the view and that the form position |
|
2231 // is correct. |
|
2232 // --------------------------------------------------------- |
|
2233 // |
|
2234 TBool CMsgEditorView::EnsureCorrectFormPosition( TBool /*aScrollDown*/, TBool /*aScrollUp*/ ) |
|
2235 { |
|
2236 CMsgBaseControl* ctrl = FocusedControl(); |
|
2237 if ( !ctrl ) |
|
2238 { |
|
2239 return EFalse; |
|
2240 } |
|
2241 |
|
2242 iStateFlags |= EMsgEnsureCorrectFormPositionRequestIssued; |
|
2243 |
|
2244 TInt delta = 0; |
|
2245 TBool viewScrolled = ETrue; |
|
2246 TRect lineRect = ctrl->IsReadOnly() ? ctrl->Rect() : |
|
2247 ctrl->CurrentLineRect(); |
|
2248 |
|
2249 if ( lineRect.Height() ) |
|
2250 { |
|
2251 if ( lineRect.iBr.iY > iViewRect.Height() ) |
|
2252 { |
|
2253 // the view must be scrolled up. |
|
2254 delta = iViewRect.Height() - lineRect.iBr.iY; |
|
2255 } |
|
2256 else if ( lineRect.iTl.iY < 0 && |
|
2257 lineRect.Height() <= iViewRect.Height() ) |
|
2258 { |
|
2259 // the view must be scrolled down. |
|
2260 delta = -lineRect.iTl.iY; |
|
2261 } |
|
2262 |
|
2263 // Adjust to next(/previous) baseline |
|
2264 if ( delta > 0 ) |
|
2265 { |
|
2266 MsgEditorCommons::RoundToNextLine( delta, iLineHeight ); |
|
2267 } |
|
2268 else |
|
2269 { |
|
2270 MsgEditorCommons::RoundToPreviousLine( delta, iLineHeight ); |
|
2271 } |
|
2272 } |
|
2273 |
|
2274 if ( delta ) |
|
2275 { |
|
2276 EnsureCorrectCursorPosition(); |
|
2277 |
|
2278 viewScrolled = EFalse; |
|
2279 ScrollForm( delta, ETrue ); |
|
2280 } |
|
2281 |
|
2282 iStateFlags &= ~EMsgEnsureCorrectFormPositionRequestIssued; |
|
2283 |
|
2284 return viewScrolled; |
|
2285 } |
|
2286 |
|
2287 // --------------------------------------------------------- |
|
2288 // CMsgEditorView::HandleHeightChangedL |
|
2289 // |
|
2290 // Handles the form's height change. Gets pointer aControl to a control which |
|
2291 // height is changing. If aDeltaHeight > 0 the height is increasing. |
|
2292 // Assumes that control's size has already been changed. |
|
2293 // --------------------------------------------------------- |
|
2294 // |
|
2295 TBool CMsgEditorView::HandleHeightChangedL( CMsgBaseControl* /*aControl*/, |
|
2296 TInt /*aDeltaHeight*/ ) |
|
2297 { |
|
2298 MEBLOGGER_ENTERFN( "CMsgEditorView::HandleHeightChangedL" ); |
|
2299 |
|
2300 TSize headerSize = iHeader->Size(); |
|
2301 |
|
2302 TSize size( headerSize + iBody->Size() ); |
|
2303 TSize thisSize( iViewRect.Size() ); |
|
2304 |
|
2305 SetAndGetSizeL( thisSize, EFalse ); |
|
2306 |
|
2307 if ( size.iHeight != thisSize.iHeight ) |
|
2308 { |
|
2309 SizeChanged(); |
|
2310 } |
|
2311 |
|
2312 if ( ViewInitialized() ) |
|
2313 { |
|
2314 if ( headerSize != iHeader->Size() ) |
|
2315 { |
|
2316 DrawNow(); |
|
2317 } |
|
2318 else |
|
2319 { |
|
2320 DrawDeferred(); |
|
2321 } |
|
2322 } |
|
2323 |
|
2324 MEBLOGGER_ENTERFN( "CMsgEditorView::HandleHeightChangedL" ); |
|
2325 |
|
2326 return ETrue; |
|
2327 } |
|
2328 |
|
2329 // --------------------------------------------------------- |
|
2330 // CMsgEditorView::ScrollForm |
|
2331 // |
|
2332 // Scrolls the form up or down depending on aDelta. If aDelta > 0, the form |
|
2333 // scrolls down. Form offset should also be less or equal to 0. |
|
2334 // --------------------------------------------------------- |
|
2335 // |
|
2336 TBool CMsgEditorView::ScrollForm( TInt aDelta, TBool aUpdateScrollBarPos ) |
|
2337 { |
|
2338 TBool result( ETrue ); |
|
2339 |
|
2340 if ( iFormOffset + aDelta > 0 ) |
|
2341 { |
|
2342 // Scrolling form given amount of pixels would result form to go above |
|
2343 // it's uppermost position. |
|
2344 aDelta = -iFormOffset; |
|
2345 |
|
2346 result = EFalse; |
|
2347 } |
|
2348 |
|
2349 if ( aDelta != 0 ) |
|
2350 { |
|
2351 iFormOffset += aDelta; |
|
2352 |
|
2353 // Real scrolling is performed here. |
|
2354 SizeChanged(); |
|
2355 |
|
2356 // Do not redraw the screen if we are in the middle of state refreshing. |
|
2357 if ( !( iStateFlags & EMsgStateRefreshing ) ) |
|
2358 { |
|
2359 DrawNow(); |
|
2360 } |
|
2361 |
|
2362 NotifyControlsForEvent( EMsgViewEventFormScrolled, aDelta ); |
|
2363 |
|
2364 if ( aUpdateScrollBarPos ) |
|
2365 { |
|
2366 iViewFocusPosition -= aDelta; |
|
2367 |
|
2368 const TAknDoubleSpanScrollBarModel* model = AknScrollBarModel(); |
|
2369 |
|
2370 if ( model ) |
|
2371 { |
|
2372 iScrollBar->MoveThumbsBy( 0, -aDelta ); |
|
2373 } |
|
2374 } |
|
2375 } |
|
2376 |
|
2377 return result; |
|
2378 } |
|
2379 |
|
2380 // --------------------------------------------------------- |
|
2381 // CMsgEditorView::SetViewRect |
|
2382 // |
|
2383 // Sets view rect. |
|
2384 // --------------------------------------------------------- |
|
2385 // |
|
2386 void CMsgEditorView::SetViewRect( const TRect& /*aRect*/ ) |
|
2387 { |
|
2388 iViewRect = MsgEditorCommons::MsgMainPane(); |
|
2389 |
|
2390 Window().SetExtent( iViewRect.iTl, iViewRect.Size() ); |
|
2391 } |
|
2392 |
|
2393 // --------------------------------------------------------- |
|
2394 // CMsgEditorView::AdjustComponentDistances |
|
2395 // |
|
2396 // Set proper distances between controls to obey LAF coordinates. |
|
2397 // |
|
2398 // Note: Components must know their correct height when this function |
|
2399 // is called. |
|
2400 // --------------------------------------------------------- |
|
2401 // |
|
2402 void CMsgEditorView::AdjustComponentDistances() |
|
2403 { |
|
2404 TInt i; |
|
2405 CMsgBaseControl* ctrl; |
|
2406 TInt controlType; |
|
2407 TInt countHeader = iHeader->CountMsgControls(); |
|
2408 TInt countBody = iBody->CountMsgControls(); |
|
2409 |
|
2410 TInt baseLine = iLineHeight; |
|
2411 TInt firstComponentOffset = iBaseLineOffset; |
|
2412 |
|
2413 // beforeOffset + control height + afterOffset |
|
2414 // must be multiple of baseLine! |
|
2415 TInt beforeOffset = 0; |
|
2416 TInt afterOffset = 0; |
|
2417 TInt distance = 0; |
|
2418 |
|
2419 for ( i = 0; i < countHeader; i++ ) |
|
2420 { |
|
2421 ctrl = iHeader->MsgControl( i ); |
|
2422 if ( ctrl ) |
|
2423 { |
|
2424 controlType = ctrl->ControlType(); |
|
2425 |
|
2426 if ( controlType == EMsgAddressControl || |
|
2427 controlType == EMsgExpandableControl || |
|
2428 controlType == EMsgAttachmentControl ) |
|
2429 { |
|
2430 distance = ( i == 0 ) ? firstComponentOffset : |
|
2431 0; |
|
2432 distance += afterOffset; |
|
2433 |
|
2434 // At least in APAC there's offset in the header |
|
2435 // fields. A header field is 21 pixels high whereas |
|
2436 // the baseline is 19 pixels. |
|
2437 TInt offset = -( ctrl->Size().iHeight % baseLine ); |
|
2438 // TODO: Minor MAGIC |
|
2439 // header frames take 3 pixels so it's ok to |
|
2440 // have offset of "-3". |
|
2441 if ( offset < -3 ) |
|
2442 { |
|
2443 offset += baseLine; |
|
2444 } |
|
2445 // divide offset evenly between before and after offset |
|
2446 //beforeOffset = offset / 2; |
|
2447 //afterOffset = offset - beforeOffset; |
|
2448 //distance += beforeOffset; |
|
2449 distance += offset; |
|
2450 |
|
2451 ctrl->SetDistanceFromComponentAbove( distance ); |
|
2452 } |
|
2453 } |
|
2454 } |
|
2455 |
|
2456 for ( i = 0; i < countBody; i++ ) |
|
2457 { |
|
2458 ctrl = iBody->MsgControl( i ); |
|
2459 |
|
2460 if ( ctrl ) |
|
2461 { |
|
2462 if ( i == 0 ) |
|
2463 { |
|
2464 distance = ( countHeader == 0 ) ? firstComponentOffset : |
|
2465 0; |
|
2466 } |
|
2467 else |
|
2468 { |
|
2469 distance = baseLine; |
|
2470 } |
|
2471 |
|
2472 distance += afterOffset; |
|
2473 |
|
2474 controlType = ctrl->ControlType(); |
|
2475 |
|
2476 switch ( controlType ) |
|
2477 { |
|
2478 case EMsgImageControl: |
|
2479 case EMsgAudioControl: |
|
2480 { |
|
2481 // Image control height is always |
|
2482 // multiple of baseLine |
|
2483 beforeOffset = 0; |
|
2484 afterOffset = 0; |
|
2485 break; |
|
2486 } |
|
2487 case EMsgVideoControl: |
|
2488 { |
|
2489 // Video must be precisely at the top of the screen. |
|
2490 beforeOffset = -firstComponentOffset; |
|
2491 // Video control height is not multiple of baseLine |
|
2492 // -> calculate offset |
|
2493 afterOffset = firstComponentOffset - |
|
2494 ( ctrl->Size().iHeight % baseLine ); |
|
2495 break; |
|
2496 } |
|
2497 default: |
|
2498 { |
|
2499 beforeOffset = 0; |
|
2500 afterOffset = 0; |
|
2501 break; |
|
2502 } |
|
2503 } |
|
2504 distance += beforeOffset; |
|
2505 |
|
2506 ctrl->SetDistanceFromComponentAbove( distance ); |
|
2507 |
|
2508 // TODO: Is this the correct place to check this?! |
|
2509 if ( !IsReadOnly() && |
|
2510 ( controlType == EMsgBodyControl || |
|
2511 controlType == EMsgXhtmlBodyControl ) ) |
|
2512 { |
|
2513 TUint32 flags = ctrl->ControlModeFlags(); |
|
2514 if ( iBody->ComponentIndexFromId( EMsgComponentIdBody ) == |
|
2515 countBody - 1 ) |
|
2516 { |
|
2517 // In editor mode bodycontrol must have max height |
|
2518 // if it's the last control in msg body even if it |
|
2519 // has no text so that all editor lines are drawn. |
|
2520 flags |= EMsgControlModeBodyMaxHeight; |
|
2521 } |
|
2522 else |
|
2523 { |
|
2524 flags &= ~EMsgControlModeBodyMaxHeight; |
|
2525 } |
|
2526 |
|
2527 ctrl->SetControlModeFlags( flags ); |
|
2528 } |
|
2529 } |
|
2530 } |
|
2531 } |
|
2532 |
|
2533 // --------------------------------------------------------- |
|
2534 // CMsgEditorView::SetComponentsInitialized |
|
2535 // |
|
2536 // Set all controls initialized. |
|
2537 // --------------------------------------------------------- |
|
2538 // |
|
2539 void CMsgEditorView::SetComponentsInitialized() |
|
2540 { |
|
2541 TInt i; |
|
2542 CMsgBaseControl* ctrl; |
|
2543 TInt countHeader = iHeader->CountMsgControls(); |
|
2544 TInt countBody = iBody->CountMsgControls(); |
|
2545 |
|
2546 TUint32 flags; |
|
2547 |
|
2548 for ( i = 0; i < countHeader; i++ ) |
|
2549 { |
|
2550 ctrl = iHeader->MsgControl( i ); |
|
2551 |
|
2552 if ( ctrl ) |
|
2553 { |
|
2554 flags = ctrl->ControlModeFlags(); |
|
2555 flags |= EMsgControlModeInitialized; |
|
2556 ctrl->SetControlModeFlags( flags ); |
|
2557 } |
|
2558 } |
|
2559 |
|
2560 for ( i = 0; i < countBody; i++ ) |
|
2561 { |
|
2562 ctrl = iBody->MsgControl( i ); |
|
2563 |
|
2564 if ( ctrl ) |
|
2565 { |
|
2566 flags = ctrl->ControlModeFlags(); |
|
2567 flags |= EMsgControlModeInitialized; |
|
2568 ctrl->SetControlModeFlags( flags ); |
|
2569 } |
|
2570 } |
|
2571 } |
|
2572 |
|
2573 |
|
2574 // --------------------------------------------------------- |
|
2575 // CMsgEditorView::SetAfterFocusL |
|
2576 // |
|
2577 // |
|
2578 // |
|
2579 // --------------------------------------------------------- |
|
2580 // |
|
2581 TBool CMsgEditorView::SetAfterFocusL( MMsgEditorObserver::TMsgAfterFocusEventFunc aAfterFocus ) |
|
2582 { |
|
2583 TBool forceScrollUp = EFalse; |
|
2584 CMsgBaseControl* ctrl; |
|
2585 TInt newFocus; |
|
2586 CMsgBodyControl* body = static_cast<CMsgBodyControl*>( ControlById( EMsgComponentIdBody ) ); |
|
2587 CEikRichTextEditor* bodyEditor = NULL; |
|
2588 |
|
2589 if ( body ) |
|
2590 { |
|
2591 bodyEditor = &body->Editor(); |
|
2592 body->SetupAutomaticFindAfterFocusChangeL( |
|
2593 aAfterFocus == MMsgEditorObserver::EMsgCursorToBodyBeginning ); |
|
2594 } |
|
2595 |
|
2596 if ( aAfterFocus == MMsgEditorObserver::EMsgCursorToBodyBeginning ) |
|
2597 { |
|
2598 newFocus = iBody->FirstFocusableControl( 0, EMsgFocusDown ); |
|
2599 |
|
2600 if ( newFocus != KErrNotFound ) |
|
2601 { |
|
2602 ctrl = iBody->MsgControl( newFocus ); |
|
2603 SetFocusByControlIdL( ctrl->ControlId() ); |
|
2604 |
|
2605 if ( bodyEditor ) |
|
2606 { |
|
2607 bodyEditor->SetCursorPosL( 0, EFalse ); |
|
2608 } |
|
2609 } |
|
2610 } |
|
2611 else if ( aAfterFocus == MMsgEditorObserver::EMsgCursorToBodyEnd ) |
|
2612 { |
|
2613 newFocus = iBody->FirstFocusableControl( iBody->CountMsgControls() - 1, EMsgFocusUp ); |
|
2614 |
|
2615 if ( newFocus == KErrNotFound ) |
|
2616 { |
|
2617 // empty body perhaps... |
|
2618 newFocus = iHeader->FirstFocusableControl( iHeader->CountMsgControls() - 1, EMsgFocusUp ); |
|
2619 |
|
2620 if ( newFocus != KErrNotFound ) |
|
2621 { |
|
2622 ctrl = iHeader->MsgControl( newFocus ); |
|
2623 SetFocusByControlIdL( ctrl->ControlId(), EFalse ); |
|
2624 } |
|
2625 } |
|
2626 else |
|
2627 { |
|
2628 ctrl = iBody->MsgControl( newFocus ); |
|
2629 SetFocusByControlIdL( ctrl->ControlId(), EFalse ); |
|
2630 |
|
2631 if ( bodyEditor ) |
|
2632 { |
|
2633 bodyEditor->SetCursorPosL( bodyEditor->TextLength(), EFalse ); |
|
2634 } |
|
2635 |
|
2636 forceScrollUp = ETrue; |
|
2637 } |
|
2638 } |
|
2639 return forceScrollUp; |
|
2640 } |
|
2641 |
|
2642 // --------------------------------------------------------- |
|
2643 // CMsgEditorView::ItemFinder |
|
2644 // |
|
2645 // --------------------------------------------------------- |
|
2646 // |
|
2647 EXPORT_C CItemFinder* CMsgEditorView::ItemFinder() |
|
2648 { |
|
2649 if ( iBody ) |
|
2650 { |
|
2651 CMsgBaseControl* ctrl; |
|
2652 TInt countBody = iBody->CountMsgControls(); |
|
2653 |
|
2654 for ( TInt i = 0; i < countBody; i++ ) |
|
2655 { |
|
2656 ctrl = iBody->MsgControl( i ); |
|
2657 if ( ctrl && |
|
2658 ( ctrl->ControlType() == EMsgBodyControl || |
|
2659 ctrl->ControlType() == EMsgXhtmlBodyControl ) ) |
|
2660 { |
|
2661 return ctrl->ItemFinder(); |
|
2662 } |
|
2663 } |
|
2664 } |
|
2665 return 0; |
|
2666 } |
|
2667 |
|
2668 // --------------------------------------------------------- |
|
2669 // CMsgEditorView::SetEdwinObserverL |
|
2670 // |
|
2671 // --------------------------------------------------------- |
|
2672 // |
|
2673 EXPORT_C void CMsgEditorView::SetEdwinObserverL( MEikEdwinObserver* aObserver ) |
|
2674 { |
|
2675 iEdwinObserver = aObserver; |
|
2676 |
|
2677 TInt headerControlCount = iHeader->CountMsgControls(); |
|
2678 TInt controlCount = headerControlCount + iBody->CountMsgControls(); |
|
2679 |
|
2680 for ( TInt controlIndex = 0; controlIndex < controlCount; controlIndex++ ) |
|
2681 { |
|
2682 CMsgBaseControl* control = NULL; |
|
2683 if ( controlIndex < headerControlCount ) |
|
2684 { |
|
2685 control = iHeader->MsgControl( controlIndex ); |
|
2686 } |
|
2687 else |
|
2688 { |
|
2689 control = iBody->MsgControl( controlIndex - headerControlCount ); |
|
2690 } |
|
2691 |
|
2692 CEikRichTextEditor* editor = NULL; |
|
2693 if ( control->ControlType() == EMsgExpandableControl || |
|
2694 control->ControlType() == EMsgAddressControl ) |
|
2695 { |
|
2696 editor = &static_cast<CMsgExpandableControl*>( control )->Editor(); |
|
2697 } |
|
2698 else if ( control->ControlType() == EMsgBodyControl || |
|
2699 control->ControlType() == EMsgXhtmlBodyControl ) |
|
2700 { |
|
2701 editor = &static_cast<CMsgBodyControl*>( control )->Editor(); |
|
2702 } |
|
2703 |
|
2704 if ( editor ) |
|
2705 { |
|
2706 editor->RemoveEdwinObserver( iEdwinObserver ); |
|
2707 |
|
2708 if ( iEdwinObserver ) |
|
2709 { |
|
2710 editor->AddEdwinObserverL( iEdwinObserver ); |
|
2711 } |
|
2712 } |
|
2713 } |
|
2714 } |
|
2715 |
|
2716 // --------------------------------------------------------- |
|
2717 // CMsgEditorView::ControlFullyVisible |
|
2718 // |
|
2719 // If control's: |
|
2720 // - top Y-coordinate is below or equal messaging main pane top Y-coordinate and |
|
2721 // - bottom Y-coordinate is above or equal messaging main pane bottom Y-coordinate |
|
2722 // then control is fully visible. Currently all controls are expected |
|
2723 // to have equal width as messaging data pane. |
|
2724 // --------------------------------------------------------- |
|
2725 // |
|
2726 TBool CMsgEditorView::ControlFullyVisible( CMsgBaseControl* aControl ) const |
|
2727 { |
|
2728 TBool retVal = EFalse; |
|
2729 |
|
2730 if ( aControl ) |
|
2731 { |
|
2732 TRect rect = aControl->Rect(); |
|
2733 if ( rect.iTl.iY >= 0 && |
|
2734 rect.iBr.iY <= MsgEditorCommons::EditorViewHeigth() ) |
|
2735 { |
|
2736 retVal = ETrue; |
|
2737 } |
|
2738 } |
|
2739 |
|
2740 return retVal; |
|
2741 } |
|
2742 |
|
2743 // --------------------------------------------------------- |
|
2744 // CMsgEditorView::NextFocusableFormControl |
|
2745 // |
|
2746 // Searches then next focusable form control from given form component |
|
2747 // starting from certain control and proceeding into given direction. |
|
2748 // |
|
2749 // Stops when either focusable control is found or there is no more |
|
2750 // controls left. See CMsgEditorView::IsFocusable function for |
|
2751 // description when control is focusable. |
|
2752 // --------------------------------------------------------- |
|
2753 // |
|
2754 TInt CMsgEditorView::NextFocusableFormControl( CMsgFormComponent* aFormComponent, |
|
2755 TInt aStart, |
|
2756 TMsgFocusDirection aDirection ) |
|
2757 { |
|
2758 TInt newFocus = aFormComponent->FirstFocusableControl( aStart, aDirection ); |
|
2759 TBool found = EFalse; |
|
2760 |
|
2761 while ( newFocus != KErrNotFound && |
|
2762 !found ) |
|
2763 { |
|
2764 found = IsFocusable( aFormComponent->MsgControl( newFocus ), aDirection ); |
|
2765 |
|
2766 if ( !found ) |
|
2767 { |
|
2768 newFocus = aFormComponent->FirstFocusableControl( |
|
2769 aDirection == EMsgFocusDown ? newFocus + 1 : |
|
2770 newFocus - 1, |
|
2771 aDirection ); |
|
2772 } |
|
2773 } |
|
2774 |
|
2775 return newFocus; |
|
2776 } |
|
2777 |
|
2778 // --------------------------------------------------------- |
|
2779 // CMsgEditorView::MopSupplyObject |
|
2780 // |
|
2781 // --------------------------------------------------------- |
|
2782 // |
|
2783 EXPORT_C TTypeUid::Ptr CMsgEditorView::MopSupplyObject( TTypeUid aId ) |
|
2784 { |
|
2785 if ( aId.iUid == MAknsControlContext::ETypeId ) |
|
2786 { |
|
2787 return MAknsControlContext::SupplyMopObject( aId, iBgContext ); |
|
2788 } |
|
2789 |
|
2790 return CCoeControl::MopSupplyObject( aId ); |
|
2791 } |
|
2792 |
|
2793 // --------------------------------------------------------- |
|
2794 // CMsgEditorView::HandleScrollEventL |
|
2795 // |
|
2796 // --------------------------------------------------------- |
|
2797 // |
|
2798 #ifdef RD_SCALABLE_UI_V2 |
|
2799 void CMsgEditorView::HandleScrollEventL( CEikScrollBar* aScrollBar, |
|
2800 TEikScrollEvent aEventType ) |
|
2801 { |
|
2802 switch ( aEventType ) |
|
2803 { |
|
2804 case EEikScrollUp: |
|
2805 { |
|
2806 ScrollViewL( iLineHeight, EMsgScrollUp, ETrue ); |
|
2807 EnsureCorrectScrollPartL( AknScrollBarModel()->FocusPosition() ); |
|
2808 break; |
|
2809 } |
|
2810 case EEikScrollDown: |
|
2811 { |
|
2812 ScrollViewL( iLineHeight, EMsgScrollDown, ETrue ); |
|
2813 EnsureCorrectScrollPartL( AknScrollBarModel()->FocusPosition() ); |
|
2814 break; |
|
2815 } |
|
2816 case EEikScrollTop: |
|
2817 { |
|
2818 // Not supported yet. |
|
2819 break; |
|
2820 } |
|
2821 case EEikScrollBottom: |
|
2822 { |
|
2823 // Not supported yet. |
|
2824 break; |
|
2825 } |
|
2826 case EEikScrollThumbReleaseVert: |
|
2827 { |
|
2828 iScrollBar->DrawBackground( ETrue, ETrue ); |
|
2829 |
|
2830 EnsureCorrectScrollPartL( AknScrollBarModel()->FocusPosition() ); |
|
2831 iPopUpPart = -1; |
|
2832 break; |
|
2833 } |
|
2834 case EEikScrollPageUp: |
|
2835 case EEikScrollPageDown: |
|
2836 { |
|
2837 TInt scrolledPixels = iViewFocusPosition - AknScrollBarModel()->FocusPosition(); |
|
2838 |
|
2839 // Round to the previous full line. |
|
2840 MsgEditorCommons::RoundToPreviousLine( scrolledPixels, iLineHeight ); |
|
2841 |
|
2842 if ( scrolledPixels != 0 ) |
|
2843 { |
|
2844 ScrollViewL( Abs( scrolledPixels ), |
|
2845 scrolledPixels > 0 ? EMsgScrollUp : |
|
2846 EMsgScrollDown, |
|
2847 EFalse ); |
|
2848 |
|
2849 EnsureCorrectScrollPartL( AknScrollBarModel()->FocusPosition() ); |
|
2850 |
|
2851 iScrollBar->DrawScrollBarsNow(); |
|
2852 } |
|
2853 break; |
|
2854 } |
|
2855 case EEikScrollThumbDragVert: |
|
2856 { |
|
2857 TInt currentPart( CurrentScrollPart( AknScrollBarModel()->FocusPosition() ) ); |
|
2858 |
|
2859 if ( currentPart == iVisiblePart ) |
|
2860 { |
|
2861 if ( iPopUpPart != -1 ) |
|
2862 { |
|
2863 // Hide the popup if visible |
|
2864 static_cast<CAknDoubleSpanScrollBar*>( aScrollBar )->SetScrollPopupInfoTextL( KNullDesC ); |
|
2865 iPopUpPart = -1; |
|
2866 } |
|
2867 } |
|
2868 |
|
2869 if ( iPopUpPart == -1 ) |
|
2870 { |
|
2871 TInt scrolledPixels = iViewFocusPosition - AknScrollBarModel()->FocusPosition(); |
|
2872 |
|
2873 // Round to the previous full line. |
|
2874 MsgEditorCommons::RoundToPreviousLine( scrolledPixels, iLineHeight ); |
|
2875 |
|
2876 if ( scrolledPixels != 0 ) |
|
2877 { |
|
2878 ScrollViewL( Abs( scrolledPixels ), |
|
2879 scrolledPixels > 0 ? EMsgScrollUp : |
|
2880 EMsgScrollDown, |
|
2881 EFalse ); |
|
2882 } |
|
2883 } |
|
2884 |
|
2885 TInt pixelsScrolled = iViewFocusPosition - AknScrollBarModel()->FocusPosition(); |
|
2886 TMsgScrollDirection scrollDirection = pixelsScrolled > 0 ? EMsgScrollUp : EMsgScrollDown; |
|
2887 |
|
2888 // If scrolled position is outside of visible part, then there is no need to |
|
2889 // reset thumb position and no page number pop-up need be shown. |
|
2890 if ( ( currentPart != iVisiblePart ) && |
|
2891 EnsureVisiblePartScrollComplete ( AknScrollBarModel()->FocusPosition(), scrollDirection ) ) |
|
2892 { |
|
2893 // Thumb position is forced to the top most position of currently scrolled slide. |
|
2894 TInt currentHeight( 0 ); |
|
2895 TInt screenHeight = iViewRect.Height() - iBaseLineOffset; |
|
2896 |
|
2897 for ( TInt current = 0; current < currentPart; current++ ) |
|
2898 { |
|
2899 if ( current == iVisiblePart ) |
|
2900 { |
|
2901 currentHeight += iVisiblePartHeight; |
|
2902 } |
|
2903 else |
|
2904 { |
|
2905 currentHeight += screenHeight; |
|
2906 } |
|
2907 } |
|
2908 |
|
2909 iScrollBar->DrawBackground( ETrue, EFalse ); |
|
2910 iScrollBar->SetVFocusPosToThumbPos( currentHeight ); |
|
2911 |
|
2912 if ( currentPart != iPopUpPart ) |
|
2913 { |
|
2914 ShowScrollPopupInfoTextL( static_cast<CAknDoubleSpanScrollBar*>( aScrollBar ), |
|
2915 currentPart + 1 ); |
|
2916 iPopUpPart = currentPart; |
|
2917 } |
|
2918 } |
|
2919 else |
|
2920 { |
|
2921 iScrollBar->DrawScrollBarsNow(); |
|
2922 } |
|
2923 break; |
|
2924 } |
|
2925 default: |
|
2926 { |
|
2927 break; |
|
2928 } |
|
2929 } |
|
2930 } |
|
2931 #else |
|
2932 void CMsgEditorView::HandleScrollEventL( CEikScrollBar* /*aScrollBar*/, |
|
2933 TEikScrollEvent /*aEventType*/ ) |
|
2934 { |
|
2935 } |
|
2936 #endif // RD_SCALABLE_UI_V2 |
|
2937 |
|
2938 // --------------------------------------------------------- |
|
2939 // CMsgEditorView::Draw |
|
2940 // Draws skin background for the view area. With video control |
|
2941 // this should not be done since we might accidentally draw over |
|
2942 // the video frame. In this case we only draw around the video control |
|
2943 // and let the video control draw its own background when approriate. |
|
2944 // --------------------------------------------------------- |
|
2945 // |
|
2946 void CMsgEditorView::Draw( const TRect& aRect ) const |
|
2947 { |
|
2948 CWindowGc& gc = SystemGc(); |
|
2949 |
|
2950 CMsgBaseControl* videoControl = iBody->Component( EMsgComponentIdVideo ); |
|
2951 |
|
2952 TBool backgroundDrawn( EFalse ); |
|
2953 if ( !videoControl ) |
|
2954 { |
|
2955 backgroundDrawn = AknsDrawUtils::Background( |
|
2956 AknsUtils::SkinInstance(), |
|
2957 AknsDrawUtils::ControlContext( this ), |
|
2958 this, |
|
2959 gc, |
|
2960 aRect ); |
|
2961 } |
|
2962 else |
|
2963 { |
|
2964 backgroundDrawn = AknsDrawUtils::BackgroundBetweenRects( |
|
2965 AknsUtils::SkinInstance(), |
|
2966 AknsDrawUtils::ControlContext( this ), |
|
2967 this, |
|
2968 gc, |
|
2969 aRect, |
|
2970 videoControl->Rect() ); |
|
2971 } |
|
2972 |
|
2973 |
|
2974 if ( !backgroundDrawn ) |
|
2975 { |
|
2976 gc.SetBrushColor( AKN_LAF_COLOR( 0 ) ); |
|
2977 gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); |
|
2978 gc.SetPenStyle( CGraphicsContext::ENullPen ); |
|
2979 gc.DrawRect( aRect ); |
|
2980 } |
|
2981 } |
|
2982 |
|
2983 // --------------------------------------------------------- |
|
2984 // CMsgEditorView::ReportFocusMovement |
|
2985 // |
|
2986 // --------------------------------------------------------- |
|
2987 // |
|
2988 void CMsgEditorView::ReportFocusMovement( TInt aFocusEvent ) |
|
2989 { |
|
2990 CMsgBaseControl* ctrl = FocusedControl(); |
|
2991 |
|
2992 TInt controlId = ctrl ? ctrl->ControlId() : |
|
2993 EMsgComponentIdNull; |
|
2994 |
|
2995 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgHandleFocusChange, |
|
2996 &aFocusEvent, |
|
2997 &controlId, |
|
2998 NULL ); |
|
2999 } |
|
3000 |
|
3001 // --------------------------------------------------------- |
|
3002 // CMsgEditorView::ControlFromPosition |
|
3003 // |
|
3004 // --------------------------------------------------------- |
|
3005 // |
|
3006 CMsgBaseControl* CMsgEditorView::ControlFromPosition( TPoint aPosition, |
|
3007 TBool aEvaluateHitTest ) const |
|
3008 { |
|
3009 CMsgBaseControl* control = NULL; |
|
3010 |
|
3011 if ( iHeader->Rect().Contains( aPosition ) ) |
|
3012 { |
|
3013 control = iHeader->ControlFromPosition( aPosition, aEvaluateHitTest ); |
|
3014 } |
|
3015 else |
|
3016 { |
|
3017 control = iBody->ControlFromPosition( aPosition, aEvaluateHitTest ); |
|
3018 } |
|
3019 |
|
3020 return control; |
|
3021 } |
|
3022 |
|
3023 // --------------------------------------------------------- |
|
3024 // CMsgEditorView::EnsureVisiblePartScrollComplete |
|
3025 // |
|
3026 // Description |
|
3027 // --------------------------------------------------------- |
|
3028 |
|
3029 TBool CMsgEditorView::EnsureVisiblePartScrollComplete( TInt aFocusPosition, |
|
3030 TMsgScrollDirection aDirection ) |
|
3031 { |
|
3032 MEBLOGGER_ENTERFN( "CMsgEditorView::EnsureVisiblePartScrollComplete" ); |
|
3033 TInt scrollTillPosition( 0 ); |
|
3034 TBool result = ETrue; |
|
3035 |
|
3036 TInt screenHeight = MsgEditorCommons::EditorViewHeigth() - iBaseLineOffset; |
|
3037 |
|
3038 for ( TInt current = 0; current < iVisiblePart ; current++ ) |
|
3039 scrollTillPosition += screenHeight; |
|
3040 |
|
3041 if ( aDirection == EMsgScrollDown ) |
|
3042 { |
|
3043 scrollTillPosition += iVisiblePartHeight; |
|
3044 |
|
3045 if ( aFocusPosition < scrollTillPosition ) |
|
3046 result = EFalse; |
|
3047 } |
|
3048 else |
|
3049 { |
|
3050 if ( aFocusPosition > scrollTillPosition ) |
|
3051 result = EFalse; |
|
3052 } |
|
3053 |
|
3054 MEBLOGGER_LEAVEFN( "CMsgEditorView::EnsureVisiblePartScrollComplete" ); |
|
3055 return result; |
|
3056 } |
|
3057 |
|
3058 // --------------------------------------------------------- |
|
3059 // CMsgEditorView::ScrollViewL |
|
3060 // |
|
3061 // First bound check is made so that no scrolling below minimum & |
|
3062 // above maximum is performed. This might happen with out check |
|
3063 // when using scrollbar arrows. DoScrollViewL function is called |
|
3064 // to perform the real scrolling. After all scrolling is done we |
|
3065 // move the thumb position if this is requested by the caller. |
|
3066 // --------------------------------------------------------- |
|
3067 // |
|
3068 void CMsgEditorView::ScrollViewL( TInt aPixelsToScroll, |
|
3069 TMsgScrollDirection aDirection, |
|
3070 TBool aMoveThumb ) |
|
3071 { |
|
3072 MEBLOGGER_ENTERFN( "CMsgEditorView::ScrollViewL" ); |
|
3073 |
|
3074 const TAknDoubleSpanScrollBarModel* model = AknScrollBarModel(); |
|
3075 |
|
3076 // Maximum value for thumb [0..scrollSpan] |
|
3077 TInt scrollSpan = model->ScrollSpan(); |
|
3078 |
|
3079 // Position of the topmost part of the thumb |
|
3080 TInt thumbTopPos = iViewFocusPosition; |
|
3081 |
|
3082 // Position of the downmost part of the thumb |
|
3083 TInt thumbDownPos = thumbTopPos + model->WindowSize(); |
|
3084 |
|
3085 // Bound check |
|
3086 if ( ( aDirection == EMsgScrollUp && thumbTopPos <= 0 ) || |
|
3087 ( aDirection == EMsgScrollDown && thumbDownPos >= scrollSpan ) ) |
|
3088 { |
|
3089 return; |
|
3090 } |
|
3091 |
|
3092 if ( CurrentScrollPart( iViewFocusPosition ) != iVisiblePart ) |
|
3093 { |
|
3094 // No need to perform scrolling, if the visible part is completely |
|
3095 // scrolled and the new scroll position is outside the visible part |
|
3096 if ( EnsureVisiblePartScrollComplete ( iViewFocusPosition, aDirection ) ) |
|
3097 return; |
|
3098 } |
|
3099 |
|
3100 DoScrollViewL( aPixelsToScroll, aDirection ); |
|
3101 |
|
3102 if ( aMoveThumb ) |
|
3103 { |
|
3104 // Scroll bar thumb is moved only if caller requests it. Scroll bar seems to |
|
3105 // add/subtract 1 pixel depending of direction. |
|
3106 TInt directionMultiplier( -1 ); |
|
3107 if ( aDirection == EMsgScrollDown ) |
|
3108 { |
|
3109 directionMultiplier = 1; |
|
3110 } |
|
3111 |
|
3112 iScrollBar->SetVFocusPosToThumbPos( model->FocusPosition() - |
|
3113 directionMultiplier * 1 + |
|
3114 directionMultiplier * aPixelsToScroll ); |
|
3115 } |
|
3116 |
|
3117 MEBLOGGER_LEAVEFN( "CMsgEditorView::ScrollViewL" ); |
|
3118 } |
|
3119 |
|
3120 // --------------------------------------------------------- |
|
3121 // CMsgEditorView::EnsureCorrectCursorPosition |
|
3122 // |
|
3123 // Ensures that cursor position relative to focus position |
|
3124 // on all controls is on correct position. |
|
3125 // --------------------------------------------------------- |
|
3126 // |
|
3127 void CMsgEditorView::EnsureCorrectCursorPosition() |
|
3128 { |
|
3129 CMsgFormComponent* currentForm = NULL; |
|
3130 if ( iCurrentFocus == EMsgHeaderFocused ) |
|
3131 { |
|
3132 iBody->NotifyControlsForEvent( EMsgViewEventSetCursorFirstPos, 0 ); |
|
3133 currentForm = iHeader; |
|
3134 } |
|
3135 else |
|
3136 { |
|
3137 iHeader->NotifyControlsForEvent( EMsgViewEventSetCursorLastPos, 0 ); |
|
3138 currentForm = iBody; |
|
3139 } |
|
3140 |
|
3141 TInt componentIndex = currentForm->ComponentIndexFromId( currentForm->FocusedControl()->ControlId() ); |
|
3142 |
|
3143 for ( TInt current = 0; current < currentForm->CountMsgControls(); current++ ) |
|
3144 { |
|
3145 CMsgBaseControl* control = currentForm->MsgControl( current ); |
|
3146 TInt currentIndex = currentForm->ComponentIndexFromId( control->ControlId() ); |
|
3147 if ( currentIndex < componentIndex ) |
|
3148 { |
|
3149 control->NotifyViewEvent( EMsgViewEventSetCursorLastPos, 0 ); |
|
3150 } |
|
3151 else if ( currentIndex > componentIndex ) |
|
3152 { |
|
3153 control->NotifyViewEvent( EMsgViewEventSetCursorFirstPos, 0 ); |
|
3154 } |
|
3155 } |
|
3156 } |
|
3157 |
|
3158 // --------------------------------------------------------- |
|
3159 // CMsgEditorView::EnsureCorrectScrollPartL |
|
3160 // |
|
3161 // Ensures that correct scroll part is visible. Performs scroll |
|
3162 // part change if focus position is outside of currently visible scroll |
|
3163 // part. |
|
3164 // --------------------------------------------------------- |
|
3165 // |
|
3166 void CMsgEditorView::EnsureCorrectScrollPartL( TInt aFocusPosition ) |
|
3167 { |
|
3168 TInt currentPart( CurrentScrollPart( aFocusPosition ) ); |
|
3169 if ( currentPart != iVisiblePart ) |
|
3170 { |
|
3171 MMsgEditorObserver::TMsgFocusEvent focusEvent = MMsgEditorObserver::EMsgFocusNone; |
|
3172 |
|
3173 if ( currentPart > iVisiblePart ) |
|
3174 { |
|
3175 focusEvent = MMsgEditorObserver::EMsgFocusAtBottom; |
|
3176 } |
|
3177 else |
|
3178 { |
|
3179 focusEvent = MMsgEditorObserver::EMsgFocusAtTop; |
|
3180 } |
|
3181 |
|
3182 MMsgEditorObserver::TMsgAfterFocusEventFunc after = |
|
3183 MMsgEditorObserver::EMsgAfterFocusNone; |
|
3184 |
|
3185 iVisiblePart = currentPart; |
|
3186 iEditorObserver.EditorObserver( MMsgEditorObserver::EMsgHandleFocusChange, |
|
3187 &focusEvent, |
|
3188 &after, |
|
3189 &iVisiblePart ); |
|
3190 |
|
3191 if ( after != MMsgEditorObserver::EMsgAfterFocusNone ) |
|
3192 { |
|
3193 SetAfterFocusL( after ); |
|
3194 } |
|
3195 |
|
3196 EnsureCorrectFormPosition( EFalse, EFalse ); |
|
3197 |
|
3198 UpdateScrollBarL(); |
|
3199 } |
|
3200 } |
|
3201 |
|
3202 // --------------------------------------------------------- |
|
3203 // CMsgEditorView::CurrentScrollPart |
|
3204 // |
|
3205 // Calculates the correct scroll part of the given focus position. |
|
3206 // Current scroll part is evaluated based on position of top & bottom |
|
3207 // of the view rectangle. If either one of the borders are on the |
|
3208 // different scroll part than visible part then that part is returned |
|
3209 // as current part. |
|
3210 // --------------------------------------------------------- |
|
3211 // |
|
3212 TInt CMsgEditorView::CurrentScrollPart( TInt aFocusPosition ) |
|
3213 { |
|
3214 TInt result( 0 ); |
|
3215 |
|
3216 TInt currentHeight( 0 ); |
|
3217 TInt topPart( -1 ); |
|
3218 TInt bottomPart( -1 ); |
|
3219 |
|
3220 TInt topPosition( aFocusPosition ); |
|
3221 TInt bottomPosition( topPosition + iViewRect.Height() - iBaseLineOffset ); |
|
3222 |
|
3223 TInt screenHeight = MsgEditorCommons::EditorViewHeigth() - iBaseLineOffset; |
|
3224 |
|
3225 for ( TInt current = 0; current < iScrollParts; current++ ) |
|
3226 { |
|
3227 if ( current == iVisiblePart ) |
|
3228 { |
|
3229 currentHeight += iVisiblePartHeight; |
|
3230 } |
|
3231 else |
|
3232 { |
|
3233 currentHeight += screenHeight; |
|
3234 } |
|
3235 |
|
3236 if ( topPart == -1 && |
|
3237 topPosition < currentHeight ) |
|
3238 { |
|
3239 topPart = current; |
|
3240 } |
|
3241 |
|
3242 if ( bottomPart == -1 && |
|
3243 bottomPosition <= currentHeight ) |
|
3244 { |
|
3245 bottomPart = current; |
|
3246 } |
|
3247 } |
|
3248 |
|
3249 if ( topPart == -1 ) |
|
3250 { |
|
3251 topPart = iScrollParts - 1; |
|
3252 } |
|
3253 |
|
3254 if ( bottomPart == -1 ) |
|
3255 { |
|
3256 bottomPart = iScrollParts - 1; |
|
3257 } |
|
3258 |
|
3259 if ( topPart == bottomPart ) |
|
3260 { |
|
3261 result = topPart; |
|
3262 } |
|
3263 else |
|
3264 { |
|
3265 if ( topPart != iVisiblePart ) |
|
3266 { |
|
3267 result = topPart; |
|
3268 } |
|
3269 else |
|
3270 { |
|
3271 result = bottomPart; |
|
3272 } |
|
3273 } |
|
3274 return result; |
|
3275 } |
|
3276 |
|
3277 // --------------------------------------------------------- |
|
3278 // CMsgEditorView::IsFocusable |
|
3279 // |
|
3280 // Determines if given control should receive focus when navigating |
|
3281 // into given direction. |
|
3282 // |
|
3283 // On editor mode (i.e. non read-only) every control is focusable. |
|
3284 // |
|
3285 // On viewer mode (i.e. read-only) control is focusable if: |
|
3286 // - force focus stop flag is set to control, |
|
3287 // - control is not fully visible on the screen, |
|
3288 // - focus change to given direction is not allowed or |
|
3289 // - there is currently focused (i.e. currently shown and |
|
3290 // highlighted) automatic finder item. |
|
3291 // --------------------------------------------------------- |
|
3292 // |
|
3293 TBool CMsgEditorView::IsFocusable( CMsgBaseControl* aControl, |
|
3294 TMsgFocusDirection aDirection ) const |
|
3295 { |
|
3296 if ( !aControl ) |
|
3297 { |
|
3298 return EFalse; |
|
3299 } |
|
3300 |
|
3301 if ( aControl->IsReadOnly() ) |
|
3302 { |
|
3303 if ( aControl->ControlModeFlags() & EMsgControlModeForceFocusStop || |
|
3304 !ControlFullyVisible( aControl ) || |
|
3305 !( aControl->IsFocusChangePossible( aDirection ) ) ) |
|
3306 { |
|
3307 return ETrue; |
|
3308 } |
|
3309 else if ( aControl->ItemFinder() ) |
|
3310 { |
|
3311 const CItemFinder::CFindItemExt& item = aControl->ItemFinder()->CurrentItemExt(); |
|
3312 |
|
3313 if ( item.iItemType != CItemFinder::ENoneSelected ) |
|
3314 { |
|
3315 return ETrue; |
|
3316 } |
|
3317 } |
|
3318 |
|
3319 return EFalse; |
|
3320 } |
|
3321 |
|
3322 return ETrue; |
|
3323 } |
|
3324 |
|
3325 // --------------------------------------------------------- |
|
3326 // CMsgEditorView::ShowScrollPopupInfoTextL |
|
3327 // |
|
3328 // Loads the info text resouce if not yet loaded. Creates correct |
|
3329 // text string based on this resource and given part number. |
|
3330 // After this sets the created info text for the scroll bar. |
|
3331 // --------------------------------------------------------- |
|
3332 // |
|
3333 void CMsgEditorView::ShowScrollPopupInfoTextL( CAknDoubleSpanScrollBar* aScrollBar, TInt aPartNumber ) |
|
3334 { |
|
3335 if ( !iScrollPopText ) |
|
3336 { |
|
3337 if ( !iCoeEnv->IsResourceAvailableL( R_QTN_MSG_PAGE_NUMBER_POPUP ) ) |
|
3338 { |
|
3339 // Load the resource file containing page number popup if it has not yet |
|
3340 // been loaded. This should not happen but better to be prepared for that also. |
|
3341 TParse parse; |
|
3342 User::LeaveIfError( parse.Set( KMsgEditorAppUiResourceFileName, |
|
3343 &KDC_RESOURCE_FILES_DIR, |
|
3344 NULL ) ); |
|
3345 |
|
3346 TFileName* fileName = new( ELeave ) TFileName( parse.FullName() ); |
|
3347 CleanupStack::PushL( fileName ); |
|
3348 |
|
3349 iResourceLoader.OpenL( *fileName ); |
|
3350 |
|
3351 CleanupStack::PopAndDestroy( fileName ); |
|
3352 } |
|
3353 |
|
3354 iScrollPopText = StringLoader::LoadL( R_QTN_MSG_PAGE_NUMBER_POPUP, iCoeEnv ); |
|
3355 } |
|
3356 |
|
3357 TBuf<KMsgMaximumScrollPartLength> buffer; |
|
3358 StringLoader::Format( buffer, *iScrollPopText, KErrNotFound, aPartNumber ); |
|
3359 |
|
3360 aScrollBar->SetScrollPopupInfoTextL( buffer ); |
|
3361 } |
|
3362 |
|
3363 // --------------------------------------------------------- |
|
3364 // CMsgEditorView::EnsureCorrectViewPosition |
|
3365 // --------------------------------------------------------- |
|
3366 // |
|
3367 void CMsgEditorView::EnsureCorrectViewPosition() |
|
3368 { |
|
3369 CMsgBaseControl* firstHeaderControl = iHeader->CountMsgControls() > 0 ? iHeader->MsgControl( 0 ) : NULL; |
|
3370 |
|
3371 CMsgBaseControl* lastControlBody = iBody->CountMsgControls() > 0 ? |
|
3372 iBody->MsgControl( iBody->CountMsgControls() - 1 ) : NULL; |
|
3373 |
|
3374 if ( firstHeaderControl && |
|
3375 firstHeaderControl->Position().iY > iBaseLineOffset ) |
|
3376 { |
|
3377 TInt pixelsToScroll( firstHeaderControl->Position().iY - iBaseLineOffset ); |
|
3378 TRAP_IGNORE( DoScrollViewL( pixelsToScroll, |
|
3379 EMsgScrollDown ) ); |
|
3380 } |
|
3381 else if ( lastControlBody && |
|
3382 lastControlBody->Rect().iBr.iY <= iViewRect.Height() - iLineHeight ) |
|
3383 { |
|
3384 TInt pixelsToScroll( iViewRect.Height() - lastControlBody->Rect().iBr.iY ); |
|
3385 TRAP_IGNORE( DoScrollViewL( pixelsToScroll, |
|
3386 EMsgScrollUp ) ); |
|
3387 } |
|
3388 else |
|
3389 { |
|
3390 |
|
3391 CMsgBaseControl* ctrl = FocusedControl(); |
|
3392 if (( ctrl && ctrl->ControlModeFlags() & EMsgControlModeBodyMaxHeight) && ctrl->VirtualHeight() < MsgEditorCommons::MaxBodyHeight() ) |
|
3393 { |
|
3394 // Special handling is required when we rotate the phone from |
|
3395 // landscape to portrait or vice versa when the Editor is placed last |
|
3396 TInt bottomYPos( ctrl->Position().iY + ctrl->VirtualHeight() ); |
|
3397 TInt distanceFromBottom( Rect().iBr.iY - bottomYPos ); |
|
3398 |
|
3399 if ( distanceFromBottom > 0 ) |
|
3400 { |
|
3401 TInt delta = Abs( iFormOffset ) < distanceFromBottom ? -iFormOffset : |
|
3402 distanceFromBottom; |
|
3403 if ( delta ) |
|
3404 { |
|
3405 ScrollForm( delta, ETrue ); |
|
3406 } |
|
3407 } |
|
3408 if ( ViewInitialized() ) |
|
3409 { |
|
3410 TRAP_IGNORE(UpdateScrollBarL()); |
|
3411 } |
|
3412 |
|
3413 } |
|
3414 else if( ctrl ) |
|
3415 { |
|
3416 TInt height( 0 ); |
|
3417 TInt pos( 0 ); |
|
3418 |
|
3419 GetVirtualFormHeightAndPos( height, pos ); |
|
3420 if(!ControlFullyVisible( ctrl ) && height > iViewRect.Height() ) |
|
3421 { |
|
3422 TInt controlPixels( Abs(ctrl->Position().iY )); |
|
3423 MsgEditorCommons::RoundToPreviousLine( controlPixels, iLineHeight ); |
|
3424 TRAP_IGNORE(DoScrollViewL(controlPixels,EMsgScrollDown)); |
|
3425 } |
|
3426 } |
|
3427 } |
|
3428 } |
|
3429 |
|
3430 // --------------------------------------------------------- |
|
3431 // CMsgEditorView::DoScrollViewL |
|
3432 // |
|
3433 // First & last loaded control is |
|
3434 // needed in order to do bound checking so that empty space above |
|
3435 // or below loaded controls isn't shown. Actual scrolling is performed |
|
3436 // so that control from first or last visible (depends about the |
|
3437 // scrolling direction) line is retrieved. If this control isn't fully |
|
3438 // visible on the scroll we try to move it as much visible as allowed |
|
3439 // by the scrollable pixels. When the control is fully visible it can |
|
3440 // perform internal scrolling if needed. When it has finished internal |
|
3441 // scrolling then we move the view one line up or down. This is continued |
|
3442 // as long as there is pixels left. After all scrolling is done we |
|
3443 // update our internal view focus position |
|
3444 // that keeps count where the focus position on the view is really |
|
3445 // located. Finally we draw the screen if needed. |
|
3446 // --------------------------------------------------------- |
|
3447 // |
|
3448 void CMsgEditorView::DoScrollViewL( TInt& aPixelsToScroll, |
|
3449 TMsgScrollDirection aDirection ) |
|
3450 { |
|
3451 MEBLOGGER_ENTERFN( "CMsgEditorView::DoScrollViewL" ); |
|
3452 |
|
3453 TInt pixelsLeftToScroll( aPixelsToScroll ); |
|
3454 |
|
3455 TInt directionMultiplier( -1 ); |
|
3456 if ( aDirection == EMsgScrollDown ) |
|
3457 { |
|
3458 directionMultiplier = 1; |
|
3459 } |
|
3460 |
|
3461 CMsgBaseControl* firstControl = iHeader->CountMsgControls() > 0 ? iHeader->MsgControl( 0 ) : |
|
3462 iBody->MsgControl( 0 ); |
|
3463 |
|
3464 CMsgBaseControl* lastControl = iBody->CountMsgControls() > 0 ? |
|
3465 iBody->MsgControl( iBody->CountMsgControls() - 1 ) : |
|
3466 iHeader->MsgControl( iHeader->CountMsgControls() - 1 ); |
|
3467 |
|
3468 while ( pixelsLeftToScroll > 0 ) |
|
3469 { |
|
3470 MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::DoScrollViewL: pixelsLeftToScroll %d "), pixelsLeftToScroll ); |
|
3471 |
|
3472 CMsgBaseControl* scrolledControl = NULL; |
|
3473 |
|
3474 if ( aDirection == EMsgScrollUp ) |
|
3475 { |
|
3476 // Control located at first visible line |
|
3477 scrolledControl = ControlFromPosition( TPoint( iViewRect.Width() / 2, iLineHeight / 2 + iBaseLineOffset ), EFalse ); |
|
3478 } |
|
3479 else |
|
3480 { |
|
3481 // Control located at last visible line |
|
3482 scrolledControl = ControlFromPosition( TPoint( iViewRect.Width() / 2, iViewRect.Height() - iLineHeight / 2 ), EFalse ); |
|
3483 } |
|
3484 |
|
3485 if ( scrolledControl ) |
|
3486 { |
|
3487 // Assumption: Control will make internal scrolling only if |
|
3488 // it's height is greater or equal to view height. |
|
3489 if ( !ControlFullyVisible( scrolledControl ) ) |
|
3490 { |
|
3491 // Calculate how many pixels needs to be scrolled in order |
|
3492 // to control be fully visible. |
|
3493 TInt controlPixels( Abs( scrolledControl->Position().iY ) ); |
|
3494 |
|
3495 if ( aDirection == EMsgScrollDown ) |
|
3496 { |
|
3497 // Round to the previous full line. |
|
3498 MsgEditorCommons::RoundToPreviousLine( controlPixels, iLineHeight ); |
|
3499 } |
|
3500 else |
|
3501 { |
|
3502 // Round to the next full line. |
|
3503 MsgEditorCommons::RoundToNextLine( controlPixels, iLineHeight ); |
|
3504 } |
|
3505 |
|
3506 // Scroll form so that control is fully visible or |
|
3507 // at minimum one line height and at maximum pixels left to scroll. |
|
3508 TInt scrollFormByPixels = Max( iLineHeight, Min( pixelsLeftToScroll, |
|
3509 controlPixels ) ); |
|
3510 |
|
3511 TInt oldYPos( scrolledControl->Position().iY ); |
|
3512 |
|
3513 // To disable drawing in the middle of scrolling. |
|
3514 iStateFlags |= EMsgStateRefreshing; |
|
3515 |
|
3516 if ( CurrentScrollPart( iViewFocusPosition - aPixelsToScroll + pixelsLeftToScroll + directionMultiplier * scrollFormByPixels ) != iVisiblePart ) |
|
3517 { |
|
3518 // Do not scroll form if scrolling would make scroll part change. |
|
3519 break; |
|
3520 } |
|
3521 |
|
3522 ScrollForm( -directionMultiplier * scrollFormByPixels, EFalse ); |
|
3523 |
|
3524 // Substract the pixels really moved. |
|
3525 pixelsLeftToScroll -= Abs( oldYPos - scrolledControl->Position().iY ); |
|
3526 |
|
3527 MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::DoScrollViewL: pixelsLeftToScroll after fully visible %d "), pixelsLeftToScroll ); |
|
3528 } |
|
3529 |
|
3530 if ( pixelsLeftToScroll > 0 ) |
|
3531 { |
|
3532 // Perform internal scrolling for the control if there is still pixels left to scroll. |
|
3533 pixelsLeftToScroll -= scrolledControl->ScrollL( pixelsLeftToScroll, aDirection ); |
|
3534 |
|
3535 MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::DoScrollViewL: pixelsLeftToScroll after internal scrolling %d "), pixelsLeftToScroll ); |
|
3536 } |
|
3537 } |
|
3538 |
|
3539 // After component's internal scrolling there is still some pixels left to scroll |
|
3540 // move the view to correction direction one line. |
|
3541 if ( pixelsLeftToScroll > 0 ) |
|
3542 { |
|
3543 // Boundary check for form scrolling. Do not scroll up (down) if first (last) control is |
|
3544 // fully visible. Also do not scroll form if scrolling would make scroll part change. |
|
3545 if ( aDirection == EMsgScrollDown ? lastControl->Rect().iBr.iY > iViewRect.Height() : |
|
3546 firstControl->Rect().iTl.iY < iViewRect.Height() && |
|
3547 CurrentScrollPart( iViewFocusPosition - aPixelsToScroll + pixelsLeftToScroll + directionMultiplier * iLineHeight ) == iVisiblePart ) |
|
3548 { |
|
3549 |
|
3550 if ( pixelsLeftToScroll > 0 ) |
|
3551 { |
|
3552 // To disable drawing in the middle of scrolling. |
|
3553 iStateFlags |= EMsgStateRefreshing; |
|
3554 |
|
3555 ScrollForm( -directionMultiplier * iLineHeight, EFalse ); |
|
3556 pixelsLeftToScroll -= iLineHeight; |
|
3557 |
|
3558 MEBLOGGER_WRITEF(_L("MEB: CMsgEditorView::DoScrollViewL: pixelsLeftToScroll after single scrolling %d "), pixelsLeftToScroll ); |
|
3559 |
|
3560 } |
|
3561 } |
|
3562 else |
|
3563 { |
|
3564 break; |
|
3565 } |
|
3566 } |
|
3567 } |
|
3568 |
|
3569 iViewFocusPosition += directionMultiplier * ( aPixelsToScroll - pixelsLeftToScroll ); |
|
3570 |
|
3571 if ( iStateFlags & EMsgStateRefreshing ) |
|
3572 { |
|
3573 iStateFlags &= ~EMsgStateRefreshing; |
|
3574 DrawNow(); |
|
3575 } |
|
3576 |
|
3577 MEBLOGGER_LEAVEFN( "CMsgEditorView::ScrollViewL" ); |
|
3578 } |
|
3579 |
|
3580 |
|
3581 // End of File |