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