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