emailuis/emailui/src/ncsaifeditor.cpp
changeset 0 8466d47a6819
child 1 12c456ceeff2
equal deleted inserted replaced
-1:000000000000 0:8466d47a6819
       
     1 /*
       
     2 * Copyright (c) 2007 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: This file implements classes CNcsAifEntry, CNcsAifEditor. 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include "emailtrace.h"
       
    21 #include <AknsDrawUtils.h>
       
    22 #include <s32mem.h>
       
    23 #include <txtrich.h>
       
    24 #include <baclipb.h>
       
    25 #include <PtiDefs.h>
       
    26 #include <StringLoader.h>
       
    27 #include <FreestyleEmailUi.rsg>
       
    28 
       
    29 #include "ncsaifeditor.h"
       
    30 #include "ncsconstants.h"
       
    31 #include "ncsaddressinputfield.h"
       
    32 #include "ncsutility.h"
       
    33 #include "FreestyleEmailUiUtilities.h"
       
    34 #include "ncsemailaddressobject.h"
       
    35 #include "FreestyleEmailUiLayoutData.h"
       
    36 #include "FSDelayedLoader.h"
       
    37 #include "FSEmail.pan"
       
    38 
       
    39 const TChar KCharAddressDelimeterSemiColon = ';';
       
    40 const TChar KCharAddressDelimeterComma = ',';
       
    41 const TChar KCharSpace = ' ';
       
    42 
       
    43 // ---------------------------------------------------------------------------
       
    44 // CNcsAifEntry::NewL
       
    45 // ---------------------------------------------------------------------------
       
    46 //
       
    47 CNcsAifEntry* CNcsAifEntry::NewL( const CNcsEmailAddressObject& aAddr )
       
    48     {
       
    49     FUNC_LOG;
       
    50     CNcsAifEntry* self = new (ELeave) CNcsAifEntry;
       
    51     CleanupStack::PushL(self);
       
    52     self->ConstructL( aAddr );
       
    53     CleanupStack::Pop(self);
       
    54     return self;
       
    55     }
       
    56 
       
    57 // ---------------------------------------------------------------------------
       
    58 // CNcsAifEntry::NewL
       
    59 // ---------------------------------------------------------------------------
       
    60 //
       
    61 CNcsAifEntry* CNcsAifEntry::NewL(
       
    62     const TDesC& aDn, 
       
    63     const TDesC& aEml,
       
    64     TBool aDisplayFull )
       
    65     {
       
    66     FUNC_LOG;
       
    67     CNcsAifEntry* self = new ( ELeave ) CNcsAifEntry;
       
    68     CleanupStack::PushL( self );
       
    69     self->ConstructL( aDn, aEml, aDisplayFull );
       
    70     CleanupStack::Pop( self );
       
    71     return self;
       
    72     }
       
    73 
       
    74 // ---------------------------------------------------------------------------
       
    75 // CNcsAifEntry::~CNcsAifEntry
       
    76 // ---------------------------------------------------------------------------
       
    77 //
       
    78 CNcsAifEntry::~CNcsAifEntry()
       
    79     {
       
    80     FUNC_LOG;
       
    81     delete iAddress;
       
    82     delete iDisplayString;
       
    83     }
       
    84 
       
    85 // ---------------------------------------------------------------------------
       
    86 // CNcsAifEntry::CNcsAifEntry
       
    87 // ---------------------------------------------------------------------------
       
    88 //
       
    89 CNcsAifEntry::CNcsAifEntry() 
       
    90     {
       
    91     FUNC_LOG;
       
    92     }
       
    93 
       
    94 // ---------------------------------------------------------------------------
       
    95 // CNcsAifEntry::ConstructL
       
    96 // ---------------------------------------------------------------------------
       
    97 //
       
    98 void CNcsAifEntry::ConstructL( const TDesC& aDn, const TDesC& aEml, TBool aDisplayFull )
       
    99     {
       
   100     FUNC_LOG;
       
   101     iAddress = CNcsEmailAddressObject::NewL( aDn, aEml );
       
   102     iAddress->SetDisplayFull( aDisplayFull );
       
   103     ConstructL();
       
   104     }
       
   105 
       
   106 // ---------------------------------------------------------------------------
       
   107 // CNcsAifEntry::ConstructL
       
   108 // ---------------------------------------------------------------------------
       
   109 //
       
   110 void CNcsAifEntry::ConstructL( const CNcsEmailAddressObject& aAddress )
       
   111     {
       
   112     FUNC_LOG;
       
   113     iAddress = CNcsEmailAddressObject::NewL( aAddress );
       
   114     ConstructL();
       
   115     }
       
   116 
       
   117 // ---------------------------------------------------------------------------
       
   118 // CNcsAifEntry::ConstructL
       
   119 // ---------------------------------------------------------------------------
       
   120 //
       
   121 void CNcsAifEntry::ConstructL() 
       
   122     {
       
   123     FUNC_LOG;
       
   124     SetDisplayStringL();
       
   125     }
       
   126 
       
   127 // ---------------------------------------------------------------------------
       
   128 // CNcsAifEntry::SetDisplayStringL
       
   129 // ---------------------------------------------------------------------------
       
   130 //
       
   131 void CNcsAifEntry::SetDisplayStringL() 
       
   132     {
       
   133     FUNC_LOG;
       
   134     delete iDisplayString;
       
   135     iDisplayString = NULL;
       
   136 
       
   137     const TDesC& dname = iAddress->DisplayName();
       
   138     const TDesC& email = iAddress->EmailAddress();
       
   139     
       
   140     TInt dnameLength = dname.Length();
       
   141     TInt emailLength = email.Length();
       
   142     
       
   143     TBool displayFull = iAddress->DisplayFull() || iIsDup;
       
   144     
       
   145     TInt length;
       
   146     // Show only display name OR email address if showing both is not required
       
   147     // or if display name doesn't contain anything but the email address
       
   148     // or if the display name is empty
       
   149     if ( !displayFull ||
       
   150          dname == email ||
       
   151          !dnameLength )
       
   152         {
       
   153         length = dnameLength > 0 ? dnameLength : emailLength;
       
   154         length += KEmailAddressSeparator().Length(); // ';'
       
   155         
       
   156         iDisplayString = HBufC::NewL( length );
       
   157         TPtr ptr = iDisplayString->Des();
       
   158         
       
   159         ptr.Append( dname.Length() > 0 ? dname : email );
       
   160         ptr.Append( KEmailAddressSeparator );
       
   161         }
       
   162     
       
   163     // Otherwise, show both display name and email addresss
       
   164     else 
       
   165         {
       
   166         // Display, Name;
       
   167         length = dnameLength + emailLength + 
       
   168             KSpace().Length() + 
       
   169             KEmailAddressDecorationHead().Length() +
       
   170             KEmailAddressDecorationTail().Length() +
       
   171             KEmailAddressSeparator().Length();
       
   172         
       
   173         iDisplayString = HBufC::NewL( length );
       
   174         TPtr ptr = iDisplayString->Des();
       
   175         
       
   176         ptr.Append( dname );
       
   177         ptr.Append( KSpace );
       
   178         ptr.Append( KEmailAddressDecorationHead );
       
   179         ptr.Append( email );
       
   180         ptr.Append( KEmailAddressDecorationTail );
       
   181         ptr.Append( KEmailAddressSeparator );
       
   182         }
       
   183     }
       
   184 
       
   185 // ---------------------------------------------------------------------------
       
   186 // CNcsAifEntry::SetDupL
       
   187 // ---------------------------------------------------------------------------
       
   188 //
       
   189 void CNcsAifEntry::SetDupL( TBool aDup ) 
       
   190     {
       
   191     FUNC_LOG;
       
   192     if ( iIsDup != aDup )
       
   193         {
       
   194         iIsDup = aDup;
       
   195         // Display string needs to be recreated unless there's no
       
   196         // meaningful display name
       
   197         if ( iAddress->DisplayName().Length() &&
       
   198              iAddress->DisplayName() != iAddress->EmailAddress() )
       
   199             {
       
   200             SetDisplayStringL();
       
   201             }
       
   202         }
       
   203     }
       
   204 
       
   205 // ---------------------------------------------------------------------------
       
   206 // CNcsAifEntry::IsSameDN
       
   207 // ---------------------------------------------------------------------------
       
   208 //
       
   209 TBool CNcsAifEntry::IsSameDN( const CNcsAifEntry& entry ) const
       
   210     {
       
   211     FUNC_LOG;
       
   212     const TDesC& ownDn = Address().DisplayName();
       
   213     const TDesC& otherDn = entry.Address().DisplayName();
       
   214     return ownDn.Compare( otherDn ) == 0;
       
   215     }
       
   216 
       
   217 // ---------------------------------------------------------------------------
       
   218 // constructor/destructor
       
   219 // ---------------------------------------------------------------------------
       
   220 //
       
   221 CNcsAifEditor::CNcsAifEditor(
       
   222     MNcsFieldSizeObserver* aSizeObserver ) 
       
   223     : CNcsEditor( aSizeObserver, ETrue, ENcsEditorAddress ), iAddressPopupList( NULL ),
       
   224     iAddLeftover( ETrue )
       
   225     {
       
   226     FUNC_LOG;
       
   227 	SetEdwinObserver( this );
       
   228     }
       
   229 
       
   230 // ---------------------------------------------------------------------------
       
   231 // second phase constructor
       
   232 // ---------------------------------------------------------------------------
       
   233 //
       
   234 void CNcsAifEditor::ConstructL( const CCoeControl* aParent,
       
   235         TInt aNumberOfLines,
       
   236         TInt aTextLimit )
       
   237     {
       
   238     FUNC_LOG;
       
   239     CNcsEditor::ConstructL( aParent, aNumberOfLines, aTextLimit );
       
   240     iAsyncCallBack = new (ELeave) CAsyncCallBack( CActive::EPriorityStandard );
       
   241     }
       
   242 
       
   243 // ---------------------------------------------------------------------------
       
   244 // destructor
       
   245 // ---------------------------------------------------------------------------
       
   246 //
       
   247 CNcsAifEditor::~CNcsAifEditor()
       
   248     {
       
   249     FUNC_LOG;
       
   250 	iArray.ResetAndDestroy();
       
   251 	iAddressArray.Reset();
       
   252 	if ( iAsyncCallBack )
       
   253 	    {
       
   254 	    iAsyncCallBack->Cancel();
       
   255 	    delete iAsyncCallBack;
       
   256 	    }
       
   257     }
       
   258 
       
   259 
       
   260 // -----------------------------------------------------------------------------
       
   261 // CNcsAifEditor::CursorLineNumber() const
       
   262 // -----------------------------------------------------------------------------
       
   263 //
       
   264 TInt CNcsAifEditor::CursorLineNumber() const
       
   265     {
       
   266     FUNC_LOG;
       
   267     
       
   268     TInt ret = iLayout->GetLineNumber( CursorPos() );
       
   269     ret++;
       
   270     return ret;    
       
   271     }
       
   272     
       
   273 // -----------------------------------------------------------------------------
       
   274 // CNcsAifEditor::LineCount() const
       
   275 // -----------------------------------------------------------------------------
       
   276 //    
       
   277 TInt CNcsAifEditor::LineCount() const
       
   278     {
       
   279     FUNC_LOG;
       
   280     TInt lineCount = iLayout->GetLineNumber( TextLength() );
       
   281     lineCount++;
       
   282     return lineCount;
       
   283     }
       
   284 
       
   285 // -----------------------------------------------------------------------------
       
   286 // CNcsAifEditor::OfferKeyEventL()
       
   287 // -----------------------------------------------------------------------------
       
   288 //
       
   289 TKeyResponse CNcsAifEditor::OfferKeyEventL( const TKeyEvent& aKeyEvent,
       
   290     TEventCode aType )
       
   291     {
       
   292     FUNC_LOG;
       
   293     TKeyResponse ret = EKeyWasNotConsumed;
       
   294 
       
   295     // check if we are copying
       
   296     if ( ret == EKeyWasNotConsumed )
       
   297         {
       
   298         ret = CopyEntriesToClipboardL( aKeyEvent, aType );
       
   299         }
       
   300 
       
   301     // Check if we need to delete a contact
       
   302     // This is done before select since they key off of the same key code.
       
   303     if ( ret == EKeyWasNotConsumed )
       
   304         {
       
   305         ret = HandleContactDeletionL( aKeyEvent, aType );
       
   306         }
       
   307 
       
   308     // Check if we need to highlight a contact
       
   309     if ( ret == EKeyWasNotConsumed )
       
   310         {
       
   311         ret = SetEditorSelectionL( aKeyEvent, aType );
       
   312         }
       
   313     
       
   314     //when press a key down, record the coursor position
       
   315     if ( aType == EEventKeyDown )
       
   316     	{
       
   317     	iLastTimeCursorPos = CursorPos();
       
   318     	}
       
   319 
       
   320     if ( ret == EKeyWasNotConsumed )
       
   321         {
       
   322         // enter completes the address entry
       
   323         if( aType == EEventKey && (aKeyEvent.iCode == EKeyEnter || 
       
   324         	aKeyEvent.iScanCode == EStdKeyEnter) )
       
   325         	{
       
   326         	// make sure there is really some text inputted 
       
   327             TInt cursorPos( CursorPos() );
       
   328         	
       
   329             TCursorSelection selection = NonEntryTextAtPos( cursorPos );
       
   330             
       
   331             TInt length( selection.Length() );
       
   332             
       
   333             HBufC* text = HBufC::NewLC( length );
       
   334             TPtr ptr = text->Des();
       
   335             Text()->Extract( ptr, selection.LowerPos(), length );
       
   336             ptr.Trim();
       
   337             
       
   338             // complete the entry by adding a semicolon, 
       
   339             // address will be added in HandleTextUpdateL
       
   340             if( ptr.Length() > 0 )
       
   341             	{            
       
   342 				Text()->InsertL( cursorPos, KCharAddressDelimeterSemiColon );
       
   343 				HandleTextChangedL();
       
   344 				SetCursorPosL( cursorPos + 1, EFalse );
       
   345             	}
       
   346             
       
   347             CleanupStack::PopAndDestroy( text );            
       
   348         	}
       
   349         
       
   350         ret = CNcsEditor::OfferKeyEventL( aKeyEvent, aType );
       
   351         }
       
   352     return ret;
       
   353     }
       
   354 
       
   355 // -----------------------------------------------------------------------------
       
   356 // CNcsAifEditor::HandleEdwinEventL()
       
   357 // This function gets called if a character is entered through the FEP.
       
   358 // Otherwise the character entry is added through OfferKeyEvent
       
   359 // -----------------------------------------------------------------------------
       
   360 //
       
   361 void CNcsAifEditor::HandleEdwinEventL( CEikEdwin* /*aEdwin*/,
       
   362     TEdwinEvent aEventType )
       
   363     {
       
   364     FUNC_LOG;
       
   365     if ( aEventType == MEikEdwinObserver::EEventTextUpdate )
       
   366         {
       
   367         // Remove any invalid entries. This is needed when entries have been marked
       
   368         // and have got replaced with some key event handled by FEP.
       
   369         CheckAndRemoveInvalidEntriesL();
       
   370         
       
   371         // Make a deferred call to HandleTextUpdateL() because it may result in
       
   372         // changing the text field contents, and doing so directly within HandleEdwinEventL
       
   373         // causes problems for the FEP in some special cases.
       
   374         HandleTextUpdateDeferred();
       
   375         }
       
   376     else if ( aEventType == MEikEdwinObserver::EEventNavigation )
       
   377         {
       
   378         HandleNavigationEventL();
       
   379         }
       
   380     }
       
   381 
       
   382 // -----------------------------------------------------------------------------
       
   383 // CNcsAifEditor::SetEditorSelectionL()
       
   384 // -----------------------------------------------------------------------------
       
   385 //   
       
   386 TKeyResponse CNcsAifEditor::SetEditorSelectionL( const TKeyEvent& aKeyEvent,
       
   387     TEventCode aType )
       
   388     {
       
   389     FUNC_LOG;
       
   390     TKeyResponse response = EKeyWasNotConsumed;
       
   391     CNcsAifEntry* entry = NULL;
       
   392     TCursorSelection selection = Selection();
       
   393     
       
   394     // Moving to a new line is a special case.
       
   395     // We need to offer the key to the editor control first so it can
       
   396     // move the cursor for us.  Then we check if it's in an entry.
       
   397     if ( aKeyEvent.iCode == EKeyUpArrow || aKeyEvent.iCode == EKeyDownArrow )
       
   398         {
       
   399     	// make sure there is really some text inputted 
       
   400         TInt cursorPos( CursorPos() );
       
   401     	
       
   402         TCursorSelection selection = NonEntryTextAtPos( cursorPos );
       
   403         
       
   404         TInt length( selection.Length() );
       
   405         
       
   406         HBufC* text = HBufC::NewLC( length );
       
   407         TPtr ptr = text->Des();
       
   408         
       
   409         if( selection.LowerPos() >= 0 )
       
   410         	{
       
   411 			Text()->Extract( ptr, selection.LowerPos(), length );
       
   412 			ptr.Trim();
       
   413 			
       
   414 			// complete the entry
       
   415 			if( ptr.Length() > 0 )
       
   416 				{
       
   417 				Text()->InsertL( selection.HigherPos(), KCharAddressDelimeterSemiColon );
       
   418 				HandleTextChangedL();
       
   419 				HandleTextUpdateL( TCursorSelection(selection.LowerPos(), selection.HigherPos() + 1) );
       
   420 				}
       
   421         	}
       
   422 		
       
   423 		CleanupStack::PopAndDestroy( text );
       
   424 		
       
   425         response = CNcsEditor::OfferKeyEventL( aKeyEvent,aType );
       
   426         if ( response == EKeyWasConsumed ) 
       
   427             {
       
   428             // We're moving to a new line.
       
   429             entry = GetEntryAt( CursorPos() );
       
   430             if ( entry )
       
   431                 {
       
   432                 SetSelectionL( entry->iCursorPos, entry->iAnchorPos );
       
   433                 }
       
   434             }
       
   435         }
       
   436     // Check if the cursor is in any of the addresses
       
   437     else if( aKeyEvent.iCode == EKeyLeftArrow || aKeyEvent.iCode == EKeyBackspace ) 
       
   438         {
       
   439         // We're moving left, but haven't yet.
       
   440         entry = GetEntryAt( CursorPos(), EDirectionLeft );
       
   441         if ( entry )
       
   442             {
       
   443             if ( selection.Length() && aKeyEvent.iCode == EKeyLeftArrow)
       
   444                 {
       
   445                 // Adds or removes the entry from the current selection.
       
   446                 SetSelectionL( entry->LowerPos(), selection.iAnchorPos );
       
   447                 response = EKeyWasConsumed;
       
   448                 }
       
   449             else if ( !selection.Length() )
       
   450                 {
       
   451                 SetSelectionL( entry->LowerPos(), entry->HigherPos() );
       
   452                 response = EKeyWasConsumed;
       
   453                 }
       
   454             }
       
   455         }
       
   456     else if( aKeyEvent.iCode == EKeyRightArrow || aKeyEvent.iCode == EKeyDelete )
       
   457         {
       
   458         // We're moving right, but haven't yet.
       
   459         entry = GetEntryAt( CursorPos(), EDirectionRight );
       
   460         if ( entry )
       
   461             {
       
   462             if ( selection.Length() && aKeyEvent.iCode == EKeyRightArrow  )
       
   463                 {
       
   464                 // Adds or removes the entry form the current selection.
       
   465                 SetSelectionL( entry->HigherPos(), selection.iAnchorPos );
       
   466                 response = EKeyWasConsumed;
       
   467                 }
       
   468             else if ( !selection.Length() )
       
   469                 {
       
   470                 SetSelectionL( entry->HigherPos(), entry->LowerPos() );
       
   471                 response = EKeyWasConsumed;
       
   472                 }
       
   473             }
       
   474         }
       
   475     // to fix problems with updating CBA when hash key is pressed and hold
       
   476     else if ( aKeyEvent.iScanCode == EStdKeyHash ) 
       
   477         {
       
   478         iAddressPopupList->ClosePopupContactListL();
       
   479         }
       
   480 
       
   481     // Close the address popup if we handled the event
       
   482     if ( response == EKeyWasConsumed )
       
   483         {
       
   484         iAddressPopupList->ClosePopupContactListL();
       
   485         }
       
   486     
       
   487     return response;
       
   488     }
       
   489 
       
   490 // ---------------------------------------------------------------------------
       
   491 // CNcsAifEditor::HandleContactDeletionL()
       
   492 // ---------------------------------------------------------------------------
       
   493 //
       
   494 TKeyResponse CNcsAifEditor::HandleContactDeletionL( const TKeyEvent& aKeyEvent,
       
   495     TEventCode aType )
       
   496     {
       
   497     FUNC_LOG;
       
   498     TKeyResponse response  = EKeyWasNotConsumed;
       
   499     if ( SelectionLength() && aType == EEventKey 
       
   500         && IsCharacterKey( aKeyEvent ) )
       
   501         {
       
   502         // Delete highlighted entries.
       
   503         TCursorSelection selection = Selection();
       
   504         TBool entryDeleted = EFalse;
       
   505         for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii )
       
   506             {
       
   507             if ( iArray[ii]->LowerPos() >= selection.LowerPos() &&
       
   508                 iArray[ii]->HigherPos() <= selection.HigherPos() )
       
   509                 {
       
   510                 delete iArray[ii];
       
   511                 iArray.Remove( ii );
       
   512                 entryDeleted = ETrue;
       
   513                 }
       
   514             }
       
   515 
       
   516         if ( entryDeleted )
       
   517             {
       
   518             // Check that duplicate entries are correctly marked.
       
   519             UpdateDuplicateEntryMarkingsL();
       
   520     
       
   521             // Set the cursor after the entry before the ones we just deleted
       
   522             CNcsAifEntry* entry = NULL;
       
   523             for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii )
       
   524                 {
       
   525                 if ( iArray[ii]->HigherPos() <= selection.LowerPos() )
       
   526                     {
       
   527                     entry = iArray[ii];
       
   528                     break;
       
   529                     }
       
   530                 }
       
   531             
       
   532             ClearSelectionL();
       
   533             
       
   534             RepositionEntriesL( entry );
       
   535 
       
   536             // The key event is set consumed only on delete and backpace
       
   537             // events, other events need to be forwarded to the editor.
       
   538             if ( aKeyEvent.iCode == EKeyDelete || 
       
   539                  aKeyEvent.iCode == EKeyBackspace )
       
   540                 {
       
   541                 response = EKeyWasConsumed;
       
   542                 }
       
   543             }
       
   544         }
       
   545     return response;
       
   546     }
       
   547 
       
   548 // ---------------------------------------------------------------------------
       
   549 // CNcsAifEditor::DoCharChangeL
       
   550 // ---------------------------------------------------------------------------
       
   551 //
       
   552 void CNcsAifEditor::DoCharChangeL()
       
   553 	{
       
   554     FUNC_LOG;
       
   555 	RecalculateEntryPositions();
       
   556 
       
   557 	TChar previousChar = CharAtPos( CursorPos() - 1 );
       
   558 	TBool sentinel = ( previousChar == KCharAddressDelimeterSemiColon || 
       
   559 	    previousChar == KCharAddressDelimeterComma );
       
   560 	if ( sentinel )
       
   561         {
       
   562         // if comma was pressed we replace it with semicolon
       
   563 		if ( previousChar == KCharAddressDelimeterComma )
       
   564             {
       
   565 			CPlainText* text = Text();
       
   566 			text->DeleteL( CursorPos() - 1, 1 );
       
   567 			text->InsertL( CursorPos() - 1, KCharAddressDelimeterSemiColon );
       
   568             }
       
   569 		ParseNewAddressL();
       
   570         }
       
   571 	UpdateAddressAutoCompletionL();
       
   572 	}
       
   573 
       
   574 // ---------------------------------------------------------------------------
       
   575 // CNcsAddressInputField::CharAtPos
       
   576 // ---------------------------------------------------------------------------
       
   577 //
       
   578 TChar CNcsAifEditor::CharAtPos( TInt aPos ) const
       
   579     {
       
   580     FUNC_LOG;
       
   581 	if ( aPos >= 0 && aPos < TextLength() )
       
   582         {
       
   583 		TBuf<1> buf;
       
   584 		Text()->Extract( buf, aPos, 1 );
       
   585 		return buf[0];
       
   586         }
       
   587 	else
       
   588         {
       
   589 		return 0;
       
   590         }
       
   591     }
       
   592 
       
   593 // -----------------------------------------------------------------------------
       
   594 // CNcsAifEditor::SetAddressesL()
       
   595 // -----------------------------------------------------------------------------
       
   596 //
       
   597 void CNcsAifEditor::SetAddressesL( const RPointerArray<CNcsEmailAddressObject>& aAddresses )
       
   598     {
       
   599     FUNC_LOG;
       
   600     iArray.Reset();
       
   601     AppendAddressesL( aAddresses );
       
   602     }
       
   603 
       
   604 // -----------------------------------------------------------------------------
       
   605 // CNcsAifEditor::AppendAddressesL()
       
   606 // -----------------------------------------------------------------------------
       
   607 //
       
   608 void CNcsAifEditor::AppendAddressesL( const RPointerArray<CNcsEmailAddressObject>& aAddresses )
       
   609     {
       
   610     FUNC_LOG;
       
   611     // First, add all the addresses without updating the editor text contents 
       
   612     for ( TInt i=0 ; i<aAddresses.Count() ; i++ )
       
   613         {
       
   614     	AddAddressL( *aAddresses[i], EFalse );
       
   615         }
       
   616     // Update editor text content after all the items have been added
       
   617     RepositionEntriesL( NULL );
       
   618     }
       
   619 
       
   620 // -----------------------------------------------------------------------------
       
   621 // CNcsAifEditor::GetAddressesL()
       
   622 // -----------------------------------------------------------------------------
       
   623 //   
       
   624 const RPointerArray<CNcsEmailAddressObject>& CNcsAifEditor::GetAddressesL()
       
   625     {
       
   626 	// Clear the existing array since it may be out of sync
       
   627 	iAddressArray.Reset();
       
   628 
       
   629 	for ( TInt i=0 ; i<iArray.Count() ; i++ ) 
       
   630         {
       
   631 		iAddressArray.AppendL(&iArray[i]->Address());
       
   632         }
       
   633 
       
   634 	return iAddressArray;
       
   635     }
       
   636     
       
   637 // -----------------------------------------------------------------------------
       
   638 // CNcsAifEditor::GetEntryAt()
       
   639 // -----------------------------------------------------------------------------
       
   640 //   
       
   641 CNcsAifEntry* CNcsAifEditor::GetEntryAt( 
       
   642     TInt aPos, 
       
   643     TEntryDirection aDirection ) const
       
   644     {
       
   645     FUNC_LOG;
       
   646     const TChar KSpace( ' ' );
       
   647 
       
   648 	for( TInt i = 0; i < iArray.Count(); i++ )
       
   649         {
       
   650         CNcsAifEntry* entry = iArray[i];
       
   651         if ( aDirection == EDirectionNone )
       
   652             {
       
   653             // no direction, check if cursor is on entry
       
   654             if ( entry->Includes( aPos ) )
       
   655                 {
       
   656                 return entry;
       
   657                 }
       
   658             }
       
   659         else if ( aDirection == EDirectionRight )
       
   660             {
       
   661             // direction to the righ. check if cursor is on entry or
       
   662             // entry is immediately to the right of the cursor
       
   663             if ( entry->Includes( aPos ) )
       
   664                 {
       
   665                 return entry;
       
   666                 }
       
   667 
       
   668             if ( entry->Start() >= aPos && entry->Start() - aPos <= 1 &&
       
   669                 CharAtPos( aPos ) == KSpace )
       
   670                 {
       
   671                 return entry;
       
   672                 }
       
   673             }
       
   674         else if ( aDirection == EDirectionLeft )
       
   675             {
       
   676             // direction to the left. decrease cursor by one and check if it
       
   677             // is on entry or if entry is immediately to the left of the cursor
       
   678             if ( entry->Includes( aPos - 1 ) )
       
   679                 {
       
   680                 return entry;
       
   681                 }
       
   682             
       
   683             if ( aPos >= entry->End() && aPos - entry->End() <= 1 &&
       
   684                 CharAtPos( aPos - 1 ) == KSpace )
       
   685                 {
       
   686                 return entry;
       
   687                 }
       
   688             }
       
   689         }
       
   690 	return NULL;
       
   691     }
       
   692 
       
   693 // -----------------------------------------------------------------------------
       
   694 // CNcsAifEditor::GetPreviousEntryFrom()
       
   695 // -----------------------------------------------------------------------------
       
   696 //
       
   697 CNcsAifEntry* CNcsAifEditor::GetPreviousEntryFrom( TInt aPos ) const
       
   698     {
       
   699     FUNC_LOG;
       
   700     CNcsAifEntry* entry = NULL;
       
   701     
       
   702     for( TInt i = 0 ; i < iArray.Count() ; i++ )
       
   703         {
       
   704         if ( iArray[i]->End() < aPos )
       
   705             {
       
   706             entry = iArray[i];
       
   707             }
       
   708         else
       
   709             {
       
   710             break;
       
   711             }
       
   712         }
       
   713     
       
   714     return entry;
       
   715     }
       
   716 
       
   717 // -----------------------------------------------------------------------------
       
   718 // CNcsAifEditor::CheckAddressWhenFocusLostL()
       
   719 // -----------------------------------------------------------------------------
       
   720 //
       
   721 void CNcsAifEditor::CheckAddressWhenFocusLostL()
       
   722     {
       
   723     FUNC_LOG;
       
   724 	ParseNewAddressL();
       
   725     }
       
   726 
       
   727 // -----------------------------------------------------------------------------
       
   728 // CNcsAifEditor::ParseNewAddressL()
       
   729 // -----------------------------------------------------------------------------
       
   730 //
       
   731 void CNcsAifEditor::ParseNewAddressL()
       
   732 	{
       
   733     FUNC_LOG;
       
   734 	HBufC* text = GetNonEntryTextLC();
       
   735 	__ASSERT_ALWAYS( text, Panic(EFSEmailUiNullPointerException) );
       
   736 
       
   737 	if ( text->Length() )
       
   738 		{
       
   739         // if changing focus leftover text is parsed to email
       
   740         // object - we don't need to add it anymore
       
   741         iAddLeftover = EFalse;
       
   742         // check if there is a name for the email address
       
   743         HBufC* name = CFsDelayedLoader::InstanceL()->GetContactHandlerL()->GetLastSearchNameL( *text );
       
   744 	if ( name )
       
   745 		{
       
   746             CleanupStack::PushL( name );
       
   747 		AddAddressL( *name, *text, ETrue );
       
   748 		CleanupStack::PopAndDestroy( name );
       
   749 		}
       
   750 	else
       
   751 		{
       
   752 		AddAddressL( KNullDesC, *text );
       
   753 		}
       
   754 	    }
       
   755 	
       
   756 	CleanupStack::PopAndDestroy(text);
       
   757 	}
       
   758 
       
   759 // -----------------------------------------------------------------------------
       
   760 // CNcsAifEditor::GetNonEntryTextL()
       
   761 // This will extract any text that was entered that is not
       
   762 // part of any existing entries
       
   763 // -----------------------------------------------------------------------------
       
   764 //
       
   765 HBufC* CNcsAifEditor::GetNonEntryTextLC() const
       
   766     {
       
   767     FUNC_LOG;
       
   768     
       
   769     // "non-entry text" starts after last "entry"
       
   770     TInt start( 0 );
       
   771     if ( iArray.Count() > 0 )
       
   772         {
       
   773         start = iArray[iArray.Count() - 1]->End();
       
   774         }
       
   775     TInt length( TextLength() - start );
       
   776 
       
   777     // Allocate space and extract it
       
   778     HBufC* text = HBufC::NewLC( length );
       
   779     TPtr ptr = text->Des();
       
   780     Text()->Extract( ptr, start, length );
       
   781     
       
   782     // Wipe out possible delimiter
       
   783     TInt pos = ptr.Locate( KCharAddressDelimeterSemiColon );
       
   784     if ( pos != KErrNotFound )
       
   785         {
       
   786         ptr.Delete( pos, 1 );
       
   787         }
       
   788     
       
   789     // Remove unnecessary whitespaces
       
   790     ptr.Trim();
       
   791     
       
   792     INFO_1("non-entry text == %S", text);
       
   793     return text;
       
   794     }
       
   795 
       
   796 // ---------------------------------------------------------------------------
       
   797 // CNcsAifEditor::CopyEntriesToClipBoardL
       
   798 // ---------------------------------------------------------------------------
       
   799 //
       
   800 TKeyResponse CNcsAifEditor::CopyEntriesToClipboardL(
       
   801     const TKeyEvent& aKeyEvent,
       
   802     TEventCode aType )
       
   803     {
       
   804     FUNC_LOG;
       
   805     TKeyResponse ret = EKeyWasNotConsumed;
       
   806     // check that we are copying
       
   807     TBool copyKeyEvent = ( aType == EEventKey && aKeyEvent.iCode == 3 &&
       
   808                            aKeyEvent.iModifiers & EModifierCtrl &&
       
   809                            aKeyEvent.iScanCode == EPtiKeyQwertyC );
       
   810     TBool cutKeyEvent = ( aType == EEventKey && aKeyEvent.iCode == 24 &&
       
   811                           aKeyEvent.iModifiers & EModifierCtrl &&
       
   812                           aKeyEvent.iScanCode == EPtiKeyQwertyX );
       
   813     if ( copyKeyEvent || cutKeyEvent ) 
       
   814         {
       
   815         RPointerArray<CNcsAifEntry> entries;
       
   816         CleanupClosePushL( entries );
       
   817         FindSelectedEntriesL( entries );
       
   818         if ( entries.Count() > 0 )
       
   819             {
       
   820             CancelFepTransaction();
       
   821             HBufC* formattedText = GetFormattedAddressListLC( entries, EFalse );
       
   822             TFsEmailUiUtility::CopyToClipboardL( *formattedText );
       
   823             CleanupStack::PopAndDestroy( formattedText );
       
   824             
       
   825             if ( !cutKeyEvent )
       
   826                 { // cutting needs more handling
       
   827                 ret = EKeyWasConsumed;
       
   828                 }
       
   829             }
       
   830         CleanupStack::PopAndDestroy( &entries );
       
   831         }
       
   832     return ret;
       
   833     }
       
   834 
       
   835 // -----------------------------------------------------------------------------
       
   836 // CNcsAifEditor::FindSelectedEntriesL( )
       
   837 // -----------------------------------------------------------------------------
       
   838 //
       
   839 void CNcsAifEditor::FindSelectedEntriesL( RPointerArray<CNcsAifEntry>& aEntries )
       
   840     {
       
   841     FUNC_LOG;
       
   842     TCursorSelection selection = Selection();
       
   843     TInt count = iArray.Count();
       
   844     for ( TInt i = 0; i < iArray.Count(); i++ )
       
   845         {
       
   846         CNcsAifEntry* entry = iArray[i];
       
   847         if ( entry->Start() >= selection.LowerPos() &&
       
   848              entry->End() <= selection.HigherPos() )
       
   849             {
       
   850             aEntries.AppendL( entry );
       
   851             }
       
   852         }
       
   853     }
       
   854 
       
   855 // -----------------------------------------------------------------------------
       
   856 // CNcsAifEditor::EmailAddressIndexNameBySelection( )
       
   857 // -----------------------------------------------------------------------------
       
   858 //
       
   859 const CNcsEmailAddressObject* CNcsAifEditor::EmailAddressObjectBySelection() const
       
   860     {
       
   861     FUNC_LOG;
       
   862 	// Find the contact the cursor is in
       
   863 	const CNcsAifEntry* aEntry = GetEntryAt(CursorPos());
       
   864 	ASSERT(aEntry != NULL);
       
   865 	return &aEntry->Address();
       
   866     }
       
   867 
       
   868 // -----------------------------------------------------------------------------
       
   869 // CNcsAifEditor::AddAddressL()
       
   870 // -----------------------------------------------------------------------------
       
   871 //
       
   872 void CNcsAifEditor::AddAddressL( const CNcsEmailAddressObject& aAddress, TBool aUpdateEditorText /*= ETrue*/ )
       
   873     {
       
   874     FUNC_LOG;
       
   875     CNcsAifEntry* entry = CNcsAifEntry::NewL( aAddress );
       
   876     CleanupStack::PushL( entry );
       
   877     AddAddressL( entry, aUpdateEditorText );
       
   878     CleanupStack::Pop( entry );
       
   879     }
       
   880 
       
   881 void CNcsAifEditor::AddAddressL( 
       
   882     const TDesC& aDisplayName, 
       
   883     const TDesC& aEmail,
       
   884     TBool aDisplayFull /*= EFalse*/,
       
   885     TBool aUpdateEditorText /*= ETrue*/ )
       
   886     {
       
   887     FUNC_LOG;
       
   888     CNcsAifEntry* entry = CNcsAifEntry::NewL( aDisplayName, aEmail, aDisplayFull );
       
   889     CleanupStack::PushL( entry );
       
   890 	AddAddressL( entry, aUpdateEditorText );
       
   891 	CleanupStack::Pop( entry );
       
   892     }
       
   893 
       
   894 void CNcsAifEditor::AddAddressL( CNcsAifEntry* aNewEntry, TBool aUpdateEditorText )
       
   895     {
       
   896     FUNC_LOG;
       
   897 	TInt idx;
       
   898 	
       
   899 	// Check for duplicate display names
       
   900 	for ( idx=0 ; idx<iArray.Count() ; idx++ ) 
       
   901         {
       
   902 		if ( iArray[idx]->IsSameDN(*aNewEntry) ) 
       
   903             {
       
   904 			iArray[idx]->SetDupL();
       
   905 			aNewEntry->SetDupL();
       
   906             }
       
   907         }
       
   908 
       
   909 	// Find the location where we need to insert the address.
       
   910 	// Browse from back to forth to make last index as default index. 
       
   911 	// This ensures items remain in correct order when populating field from
       
   912 	// existing message.
       
   913 	TInt cursorPos = CursorPos();
       
   914 	
       
   915     // if we are at the end of editor the address was
       
   916     // added from MRU list or separator was typed in
       
   917     if ( cursorPos == Text()->DocumentLength() )
       
   918         {
       
   919         iAddLeftover = EFalse;
       
   920         }
       
   921 	
       
   922 	for ( idx = iArray.Count() ; idx > 0 ; idx-- ) 
       
   923         {
       
   924 		if ( cursorPos >= iArray[idx-1]->End() ) break;
       
   925         }
       
   926 	if ( idx == iArray.Count() ) 
       
   927         {
       
   928 		// Tack the address onto the end of the array
       
   929 		iArray.AppendL( aNewEntry );
       
   930         }
       
   931 	else
       
   932         {
       
   933 		iArray.InsertL( aNewEntry, idx );
       
   934         }
       
   935 	
       
   936 	if ( aUpdateEditorText )
       
   937 	    {
       
   938 	    // Trap because we must not leave after we have taken the ownership of aNewEntry.
       
   939 	    // Otherwise douple deletion might happen.
       
   940 	    TRAP_IGNORE( RepositionEntriesL( aNewEntry ) );
       
   941 	    }
       
   942     }
       
   943 
       
   944 // ---------------------------------------------------------------------------
       
   945 // CNcsAifEditor::RecalculateEntryPositions()
       
   946 // The text has changed, so recalculate the positions of the items.
       
   947 // ---------------------------------------------------------------------------
       
   948 //	
       
   949 void CNcsAifEditor::RecalculateEntryPositions()
       
   950 	{
       
   951     FUNC_LOG;
       
   952 	// We only need to worry about items right of the cursor
       
   953 	TInt pos = CursorPos();
       
   954 	TInt error = KErrNone;
       
   955 	
       
   956 	// Find the first item to the right of the cursor
       
   957 	TInt idx = 0;
       
   958 	for ( idx = 0; idx < iArray.Count(); idx++ )
       
   959 		{
       
   960 		if ( ( iArray[idx]->Includes( iLastTimeCursorPos ) ) 
       
   961 				 || ( iArray[idx]->Start() >= iLastTimeCursorPos ) )   
       
   962 			{
       
   963 			break;
       
   964 			}
       
   965 		}	
       
   966 	
       
   967    	// If no entry was to the right of the cursor position
       
   968 	// then the new text was added at the end of the text.
       
   969 	// Don't do anything
       
   970 	if ( idx == iArray.Count() )
       
   971 		{
       
   972 		return;
       
   973 		}
       
   974 	
       
   975 	// Find the location of the first entry to the right
       
   976 	// of the cursor using a display string match
       
   977 	pos = Min( iArray[idx]->Start(), pos );
       
   978 	TRAP( error, pos = FindTextL( &iArray[idx]->DisplayString(), pos,
       
   979 	    CEikEdwin::EFindCaseSensitive | CEikEdwin::ENoBusyMessage ) );
       
   980 	ASSERT( KErrNone == error && KErrNotFound != pos );
       
   981 
       
   982 	// Now reposition all entries to the right
       
   983 	for ( ; idx<iArray.Count(); idx++ ) 
       
   984 		{
       
   985 		pos = iArray[idx]->SetPos( pos );
       
   986 		pos++; // for whitespace
       
   987 		}
       
   988 	}
       
   989 
       
   990 // ---------------------------------------------------------------------------
       
   991 // CNcsAifEditor::RepositionEntriesL()
       
   992 // ---------------------------------------------------------------------------
       
   993 //
       
   994 void CNcsAifEditor::RepositionEntriesL( const CNcsAifEntry* aPosEntry )
       
   995 	{
       
   996     FUNC_LOG;
       
   997 	TInt pos = 0;
       
   998 	CNcsAifEntry* entry;
       
   999 	for ( TInt i=0 ; i<iArray.Count() ; i++ ) 
       
  1000 		{
       
  1001 		entry = iArray[i];
       
  1002 		pos = entry->SetPos( pos );
       
  1003 		pos++; // for whitespace
       
  1004 		}
       
  1005 
       
  1006 	// Reset the text
       
  1007 	SetCursorPosL( 0, EFalse ); //In case the cursor pos is invalid
       
  1008 	HBufC* text = NULL;
       
  1009 	text = GetFormattedAddressListLC( iArray );
       
  1010 	
       
  1011     if ( iAddLeftover )
       
  1012         {
       
  1013         TInt lengthBefore = Text()->DocumentLength();
       
  1014         HBufC* textBefore = HBufC::NewLC( lengthBefore );
       
  1015         TPtr ptrBefore = textBefore->Des();
       
  1016         Text()->Extract( ptrBefore, 0, lengthBefore );
       
  1017         ptrBefore.Trim();
       
  1018         // find text after last semicolon
       
  1019         TInt colon = ptrBefore.LocateReverseF( 
       
  1020                 KCharAddressDelimeterSemiColon ) + 1;
       
  1021         TPtrC leftover = ptrBefore.Mid( colon );
       
  1022         HBufC* newText = HBufC::NewLC( text->Length() + leftover.Length() );
       
  1023         TPtr newTextPtr = newText->Des();
       
  1024         // add all email addresses
       
  1025         newTextPtr.Append( text->Des() );
       
  1026         // add the text that was after last email object
       
  1027         newTextPtr.Append( leftover );
       
  1028     
       
  1029         SetTextL( newText );
       
  1030         CleanupStack::PopAndDestroy( newText );
       
  1031         CleanupStack::PopAndDestroy( textBefore );
       
  1032         }
       
  1033     else
       
  1034         {
       
  1035         SetTextL( text );
       
  1036         }
       
  1037     CleanupStack::PopAndDestroy( text );
       
  1038     HandleTextChangedL();
       
  1039     
       
  1040     // Set the cursor at the end of the given entry 
       
  1041     if ( !aPosEntry )
       
  1042     	{
       
  1043 	    SetCursorPosL( 0, EFalse );
       
  1044     	}
       
  1045     else
       
  1046     	{
       
  1047     	SetCursorPosL( aPosEntry->End(), EFalse );
       
  1048     	}
       
  1049 	}
       
  1050 
       
  1051 // ---------------------------------------------------------------------------
       
  1052 // CNcsAifEditor::CheckAndRemoveInvalidEntriesL()
       
  1053 // ---------------------------------------------------------------------------
       
  1054 //
       
  1055 void CNcsAifEditor::CheckAndRemoveInvalidEntriesL()
       
  1056     {
       
  1057     FUNC_LOG;
       
  1058     TInt currentCursorPos( CursorPos() );
       
  1059     const TInt KNoEntryRemoved = -1;
       
  1060     TInt removedEntryIndex( KNoEntryRemoved );
       
  1061     
       
  1062     for ( TInt i = iArray.Count() - 1 ; i >= 0 ; --i )
       
  1063         {
       
  1064         TInt matchesInText;
       
  1065         TInt matchesInArray;
       
  1066         TInt arrayItemCurPos( iArray[i]->LowerPos() );
       
  1067         
       
  1068         GetMatchingEntryCountsL( iArray[i], matchesInText, matchesInArray );
       
  1069 
       
  1070         // Entry is removed if:
       
  1071         // a) there's no matches for it in the text, or
       
  1072         // b) there're less matches for it in the text than in array (i.e.,
       
  1073         //    a duplicate ("foo(at)foo.org; foo(at)foo.org") has just been removed)
       
  1074         // In b) case the correct duplicate is the one that is in current
       
  1075         // cursor position (or one off due to possible whitespace).
       
  1076         if ( 0 == matchesInText ||
       
  1077              ( matchesInText < matchesInArray &&
       
  1078                ( currentCursorPos == arrayItemCurPos || 
       
  1079                  (1 + currentCursorPos) == arrayItemCurPos ) ) )
       
  1080             {
       
  1081             delete iArray[i];
       
  1082             iArray.Remove(i);
       
  1083             removedEntryIndex = i;
       
  1084             }
       
  1085         }
       
  1086     
       
  1087     if ( KNoEntryRemoved != removedEntryIndex )
       
  1088         {
       
  1089         // at least one entry has been removed => udpates duplicate markings
       
  1090         UpdateDuplicateEntryMarkingsL();
       
  1091         }
       
  1092     }
       
  1093 
       
  1094 // ---------------------------------------------------------------------------
       
  1095 // CNcsAifEditor::GetLookupTextLC()
       
  1096 // ---------------------------------------------------------------------------
       
  1097 //
       
  1098 HBufC* CNcsAifEditor::GetLookupTextLC() const
       
  1099     {
       
  1100     FUNC_LOG;
       
  1101 	HBufC* text = GetTextInHBufL();
       
  1102 	
       
  1103 	if (text == NULL) return NULL;
       
  1104 
       
  1105 	CleanupStack::PushL( text );
       
  1106 	TPtr ptr( text->Des() );
       
  1107 	ptr = ptr.LeftTPtr( CursorPos() );
       
  1108 	TInt location = ptr.LocateReverse( KCharAddressDelimeterSemiColon );
       
  1109 	if( location != KErrNotFound )
       
  1110         {
       
  1111 		ptr = ptr.RightTPtr( ptr.Length() - location -1 );
       
  1112 		ptr.TrimLeft();
       
  1113         }
       
  1114 	return text;
       
  1115     }
       
  1116 
       
  1117 // ---------------------------------------------------------------------------
       
  1118 // CNcsAifEditor::GetFormattedAddressListLC()
       
  1119 // ---------------------------------------------------------------------------
       
  1120 //
       
  1121 HBufC* CNcsAifEditor::GetFormattedAddressListLC(
       
  1122     RPointerArray<CNcsAifEntry>& aEntries,
       
  1123     TBool aDisplayList ) const
       
  1124     {
       
  1125     FUNC_LOG;
       
  1126 	TInt length = CalculateAddressListLength( aEntries, aDisplayList );
       
  1127 	if ( length <= 0 )
       
  1128         {
       
  1129 		return HBufC::NewLC(0);
       
  1130         }
       
  1131     
       
  1132 	HBufC* buf = HBufC::NewLC( length );
       
  1133 	TPtr ptr = buf->Des();
       
  1134     
       
  1135 	TInt count = aEntries.Count();
       
  1136 	for ( TInt i = 0; i < count; i++ )
       
  1137         {
       
  1138         if ( aDisplayList )
       
  1139             {
       
  1140             ptr.Append( aEntries[i]->DisplayString() );
       
  1141             }
       
  1142         else
       
  1143             {
       
  1144             ptr.Append( aEntries[i]->Address().EmailAddress() );
       
  1145             ptr.Append( KEmailAddressSeparator );
       
  1146             }
       
  1147         
       
  1148 		// append whitespace, if not in the last entry
       
  1149         if ( i < count - 1 )
       
  1150             {
       
  1151             ptr.Append( KLineFeed );
       
  1152             }
       
  1153         }
       
  1154 		
       
  1155 	return buf;
       
  1156     }
       
  1157 
       
  1158 // ---------------------------------------------------------------------------
       
  1159 // CNcsAifEditor::GetFormattedAddressListL()
       
  1160 // ---------------------------------------------------------------------------
       
  1161 //
       
  1162 HBufC* CNcsAifEditor::GetFormattedAddressListL(
       
  1163     RPointerArray<CNcsAifEntry>& aEntries,
       
  1164     TBool aDisplayList ) const
       
  1165 	{
       
  1166     FUNC_LOG;
       
  1167     HBufC* buf = GetFormattedAddressListLC( aEntries, aDisplayList );
       
  1168     CleanupStack::Pop( buf );
       
  1169     return buf;
       
  1170 	}
       
  1171 
       
  1172 // ---------------------------------------------------------------------------
       
  1173 // CNcsAifEditor::CalculateAddressListLength()
       
  1174 // ---------------------------------------------------------------------------
       
  1175 //
       
  1176 TInt CNcsAifEditor::CalculateAddressListLength(
       
  1177     RPointerArray<CNcsAifEntry>& aEntries,
       
  1178     TBool aDisplayList ) const
       
  1179     {
       
  1180     FUNC_LOG;
       
  1181 	TInt length = 0;
       
  1182 	TInt count = aEntries.Count();
       
  1183 	for ( TInt i = 0; i < count; i++ )
       
  1184         {
       
  1185 		CNcsAifEntry* entry = aEntries[ i ];
       
  1186 		if ( !entry ) continue;
       
  1187         if ( aDisplayList )
       
  1188             {
       
  1189             length += entry->Length();
       
  1190             }
       
  1191         else
       
  1192             {
       
  1193             // +1 is for semicolon
       
  1194             length += entry->Address().EmailAddress().Length() + 1;
       
  1195             }
       
  1196         }
       
  1197 	
       
  1198 	// add one white space after that so the format is
       
  1199 	// aamiumaubb.com; ccmiumaudd.com; eemiumauff.com
       
  1200 	if ( count > 1 )
       
  1201         {
       
  1202 		// ( count - 1 ) we do need white space after the last address
       
  1203 		length += count - 1 ;
       
  1204         }
       
  1205     
       
  1206 	if ( aEntries.Count() > 0 )
       
  1207         {
       
  1208 	    length += 2;
       
  1209         }		
       
  1210 		
       
  1211 	return length;
       
  1212     }
       
  1213 
       
  1214 // ---------------------------------------------------------------------------
       
  1215 // CNcsAifEditor::UpdateAddressAutoCompletionL()
       
  1216 // ---------------------------------------------------------------------------
       
  1217 //
       
  1218 void CNcsAifEditor::UpdateAddressAutoCompletionL()
       
  1219     {
       
  1220     FUNC_LOG;
       
  1221 	HBufC* text = GetNonEntryTextLC();
       
  1222 	__ASSERT_ALWAYS( text, Panic(EFSEmailUiNullPointerException) );
       
  1223 
       
  1224 		iAddressPopupList->UpdatePopupContactListL( *text, EFalse );
       
  1225 		CleanupStack::PopAndDestroy( text );
       
  1226         }
       
  1227 
       
  1228 // ---------------------------------------------------------------------------
       
  1229 // CNcsAifEditor::UpdateAddressAutoCompletionL()
       
  1230 // ---------------------------------------------------------------------------
       
  1231 //
       
  1232 void CNcsAifEditor::UpdateAddressAutoCompletionL(
       
  1233     const TCursorSelection& aSelection )
       
  1234     {
       
  1235     FUNC_LOG;
       
  1236     TInt length = aSelection.Length();
       
  1237     HBufC* text = HBufC::NewLC( length );
       
  1238     TPtr ptr = text->Des();
       
  1239     Text()->Extract( ptr, aSelection.LowerPos(), length );
       
  1240     ptr.Trim();
       
  1241     if ( text->Length() )
       
  1242         {
       
  1243         iAddressPopupList->UpdatePopupContactListL( *text, EFalse );
       
  1244         }
       
  1245     else
       
  1246         {
       
  1247         iAddressPopupList->ClosePopupContactListL();
       
  1248         }
       
  1249     CleanupStack::PopAndDestroy( text );
       
  1250     }
       
  1251 
       
  1252 // ---------------------------------------------------------------------------
       
  1253 // CNcsAifEditor::UpdateAddressListAllL()
       
  1254 // ---------------------------------------------------------------------------
       
  1255 //
       
  1256 void CNcsAifEditor::UpdateAddressListAllL()
       
  1257     {
       
  1258     FUNC_LOG;
       
  1259 	iAddressPopupList->UpdatePopupContactListL( KNullDesC, ETrue );
       
  1260     }
       
  1261 
       
  1262 
       
  1263 // ---------------------------------------------------------------------------
       
  1264 // Updates the duplicate markings in the entry array.
       
  1265 // ---------------------------------------------------------------------------
       
  1266 //
       
  1267 void CNcsAifEditor::UpdateDuplicateEntryMarkingsL()
       
  1268     {
       
  1269     FUNC_LOG;
       
  1270     const TInt entryCount = iArray.Count();
       
  1271     for ( TInt ii = entryCount - 1; ii >= 0; --ii )
       
  1272         {
       
  1273         TBool duplicateFound = EFalse;
       
  1274         for ( TInt jj = ii - 1; jj >= 0; --jj )
       
  1275             {
       
  1276             if ( iArray[ii]->IsSameDN( *iArray[jj] ) )
       
  1277                 {
       
  1278                 duplicateFound = ETrue;
       
  1279                 iArray[jj]->SetDupL( ETrue );
       
  1280                 }
       
  1281             }
       
  1282         iArray[ii]->SetDupL( duplicateFound );
       
  1283         }
       
  1284     }
       
  1285 
       
  1286 // ---------------------------------------------------------------------------
       
  1287 // Makes a deferred call to HandleTextUpdateL
       
  1288 // ---------------------------------------------------------------------------
       
  1289 //
       
  1290 void CNcsAifEditor::HandleTextUpdateDeferred()
       
  1291     {
       
  1292     FUNC_LOG;
       
  1293     if ( iAsyncCallBack )
       
  1294         {
       
  1295         iAsyncCallBack->Cancel();
       
  1296         iAsyncCallBack->Set( TCallBack( DoHandleTextUpdate, this ) );
       
  1297         iAsyncCallBack->CallBack();
       
  1298         }
       
  1299     }
       
  1300 
       
  1301 // ---------------------------------------------------------------------------
       
  1302 // Static wrapper function for HandleTextUpdateL() 
       
  1303 // ---------------------------------------------------------------------------
       
  1304 //
       
  1305 TInt CNcsAifEditor::DoHandleTextUpdate( TAny* aSelf )
       
  1306     {
       
  1307     FUNC_LOG;
       
  1308     CNcsAifEditor* self = static_cast<CNcsAifEditor*>( aSelf );
       
  1309     TRAPD( err, self->HandleTextUpdateL() );
       
  1310     return err;
       
  1311     }
       
  1312 
       
  1313 // ---------------------------------------------------------------------------
       
  1314 // Handles text update.
       
  1315 // ---------------------------------------------------------------------------
       
  1316 //
       
  1317 void CNcsAifEditor::HandleTextUpdateL()
       
  1318     {
       
  1319     FUNC_LOG;
       
  1320     RecalculateEntryPositions();
       
  1321     TCursorSelection textSelection = NonEntryTextAtPos( CursorPos() );
       
  1322     TBool newEntryCreated = EFalse;
       
  1323     if ( textSelection.Length() )
       
  1324         {
       
  1325         // Check non-entry text for complete entries.
       
  1326         newEntryCreated = HandleTextUpdateL( textSelection );
       
  1327         }
       
  1328     
       
  1329     if ( newEntryCreated )
       
  1330         {
       
  1331         iAddressPopupList->ClosePopupContactListL();
       
  1332         
       
  1333         // add line feed after new entry
       
  1334         TInt cursorPos( CursorPos() );
       
  1335         Text()->InsertL( cursorPos, TChar(CEditableText::ELineBreak) );
       
  1336         HandleTextChangedL();
       
  1337     	SetCursorPosL( cursorPos + 1, EFalse );
       
  1338         }
       
  1339     else
       
  1340         {
       
  1341         UpdateAddressAutoCompletionL( textSelection );
       
  1342         }
       
  1343     }
       
  1344 
       
  1345 // ---------------------------------------------------------------------------
       
  1346 // CNcsAifEditor::HandleTextUpdateL()
       
  1347 // ---------------------------------------------------------------------------
       
  1348 //
       
  1349 TBool CNcsAifEditor::HandleTextUpdateL( const TCursorSelection& aSelection )
       
  1350     {
       
  1351     FUNC_LOG;
       
  1352     iAddLeftover = ETrue;
       
  1353     TInt firstCharacter = aSelection.LowerPos();
       
  1354     TInt lastCharacter = aSelection.HigherPos();
       
  1355     
       
  1356     // get the inputted text
       
  1357     TInt length = lastCharacter - firstCharacter;
       
  1358     
       
  1359     HBufC* text = HBufC::NewLC( length );
       
  1360     TPtr ptr = text->Des();
       
  1361     Text()->Extract( ptr, firstCharacter, length );
       
  1362     ptr.Trim();
       
  1363     
       
  1364     TBool entriesFound( EFalse );
       
  1365     
       
  1366     // start looking for entries separated with semicolon
       
  1367     TInt start( 0 );
       
  1368     TInt end( ptr.Length() );
       
  1369     
       
  1370     for ( TInt ii = 0; ii < end; ++ii )
       
  1371         {
       
  1372         TChar character = ptr[ii];
       
  1373         
       
  1374         if ( IsSentinel( character ) )
       
  1375             {
       
  1376             if ( character == KCharAddressDelimeterComma )
       
  1377                 {
       
  1378                 // Replace comma with semicolon
       
  1379                 ptr[ii] = KCharAddressDelimeterSemiColon;
       
  1380                 }
       
  1381 
       
  1382             // Create new entry.
       
  1383             if ( start < end )
       
  1384                 {
       
  1385                 // only if longer than 0, if not we'll get 
       
  1386                 // "empty" email address
       
  1387                 if ( ii-start )
       
  1388                     {
       
  1389                     AddAddressL( KNullDesC(), ptr.Mid(start, ii-start) );
       
  1390                     start = Min( ii + 1, end );
       
  1391                     entriesFound = ETrue;
       
  1392                     }
       
  1393                 }
       
  1394             }
       
  1395         }
       
  1396     
       
  1397     CleanupStack::PopAndDestroy( text );
       
  1398         
       
  1399     return entriesFound;
       
  1400     }
       
  1401 
       
  1402 // ---------------------------------------------------------------------------
       
  1403 // Handles navigation event.
       
  1404 // ---------------------------------------------------------------------------
       
  1405 //
       
  1406 void CNcsAifEditor::HandleNavigationEventL()
       
  1407     {
       
  1408     FUNC_LOG;
       
  1409     // Close the contact popup when cursor is moved withing the field to make it less distracting. 
       
  1410     // It's reopened when user types something.
       
  1411     iAddressPopupList->ClosePopupContactListL();
       
  1412     }
       
  1413 
       
  1414 // ---------------------------------------------------------------------------
       
  1415 // Gets the range of non-entry text at the given position.
       
  1416 // ---------------------------------------------------------------------------
       
  1417 //
       
  1418 TCursorSelection CNcsAifEditor::NonEntryTextAtPos( TUint aPosition ) const
       
  1419     {
       
  1420     FUNC_LOG;
       
  1421     TCursorSelection text( TextLength(), 0 );
       
  1422     for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii )
       
  1423         {
       
  1424         if ( iArray[ii]->Includes( aPosition - 1) )
       
  1425             {
       
  1426             // Given position is included in existing entry
       
  1427             text.SetSelection( 0, 0 );
       
  1428             break;
       
  1429             }
       
  1430         else if ( iArray[ii]->LowerPos() >= aPosition )
       
  1431             {
       
  1432             // Found entry after the given position
       
  1433             text.iCursorPos = iArray[ii]->LowerPos();
       
  1434             }
       
  1435         else if ( iArray[ii]->HigherPos() < aPosition )
       
  1436             {
       
  1437             // Found first entry before given position
       
  1438             text.iAnchorPos = iArray[ii]->HigherPos();
       
  1439             break;
       
  1440             }
       
  1441         }
       
  1442 
       
  1443     // get the selected text to remove whitespace
       
  1444     TInt length( text.Length() );    
       
  1445     
       
  1446     HBufC* selectedText = NULL;
       
  1447     TRAPD( err, selectedText = HBufC::NewL( length ) );
       
  1448     
       
  1449     if( err == KErrNone )
       
  1450     	{
       
  1451 		TPtr ptr = selectedText->Des();
       
  1452 		Text()->Extract( ptr, text.LowerPos(), length );
       
  1453 		
       
  1454 		// trim from end
       
  1455 		TInt index( length - 1 );
       
  1456 		
       
  1457 		while( index >= 0 && IsWhitespace( ptr[index--] ) )
       
  1458 			{
       
  1459 			text.iCursorPos--;
       
  1460 			}
       
  1461 		
       
  1462 		// trim from begin
       
  1463 		index = 0;
       
  1464 		
       
  1465 		while( index < length && IsWhitespace( ptr[index++] ) )
       
  1466 			{
       
  1467 			text.iAnchorPos++;
       
  1468 			}
       
  1469 
       
  1470 		delete selectedText;
       
  1471 		selectedText = NULL;
       
  1472     	}    
       
  1473     	
       
  1474     return text;
       
  1475     }
       
  1476 
       
  1477 // ---------------------------------------------------------------------------
       
  1478 // Gets the range of text immediatelly before given position that does not
       
  1479 // belong to any entry. 
       
  1480 // ---------------------------------------------------------------------------
       
  1481 //
       
  1482 TCursorSelection CNcsAifEditor::NonEntryTextBeforePos( TUint aPosition ) const
       
  1483     {
       
  1484     FUNC_LOG;
       
  1485     TCursorSelection text( aPosition, 0 );
       
  1486     for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii )
       
  1487         {
       
  1488         if ( iArray[ii]->Includes( aPosition - 1 ) )
       
  1489             {
       
  1490             // Given position is included in existing entry
       
  1491             text.SetSelection( 0, 0 );
       
  1492             break;
       
  1493             }
       
  1494         else if ( iArray[ii]->HigherPos() < aPosition )
       
  1495             {
       
  1496             // Found first existing entry before given position
       
  1497             text.SetSelection( aPosition, iArray[ii]->HigherPos() );
       
  1498             break;
       
  1499             }
       
  1500         }
       
  1501     return text;
       
  1502     }
       
  1503 
       
  1504 // ---------------------------------------------------------------------------
       
  1505 // Checks whether given character is considered as sentinel.
       
  1506 // ---------------------------------------------------------------------------
       
  1507 //
       
  1508 TBool CNcsAifEditor::IsSentinel( TChar aCharacter ) const
       
  1509     {
       
  1510     FUNC_LOG;
       
  1511     return ( aCharacter == KCharAddressDelimeterSemiColon || 
       
  1512         aCharacter == KCharAddressDelimeterComma );
       
  1513     }
       
  1514 
       
  1515 // ---------------------------------------------------------------------------
       
  1516 // Checks whether given character is considered as whitespace.
       
  1517 // ---------------------------------------------------------------------------
       
  1518 //
       
  1519 TBool CNcsAifEditor::IsWhitespace( TChar aCharacter ) const
       
  1520     {
       
  1521     FUNC_LOG;
       
  1522     return ( aCharacter == KCharSpace || 
       
  1523     		 aCharacter == TChar(CEditableText::ELineBreak) || 
       
  1524     		 aCharacter == TChar(CEditableText::EParagraphDelimiter) );
       
  1525     }
       
  1526 
       
  1527 // ---------------------------------------------------------------------------
       
  1528 // Checks whether given event is considered as navigation event.
       
  1529 // ---------------------------------------------------------------------------
       
  1530 //
       
  1531 TBool CNcsAifEditor::IsNavigationKey( const TKeyEvent& aKeyEvent ) const
       
  1532     {
       
  1533     FUNC_LOG;
       
  1534     return ( aKeyEvent.iCode == EKeyLeftArrow ||
       
  1535              aKeyEvent.iCode == EKeyRightArrow ||
       
  1536              aKeyEvent.iCode == EKeyUpArrow ||
       
  1537              aKeyEvent.iCode == EKeyDownArrow ||
       
  1538              aKeyEvent.iScanCode == EStdKeyLeftArrow ||
       
  1539              aKeyEvent.iScanCode == EStdKeyRightArrow ||
       
  1540              aKeyEvent.iScanCode == EStdKeyUpArrow ||
       
  1541              aKeyEvent.iScanCode == EStdKeyDownArrow );
       
  1542     }
       
  1543 
       
  1544 // ---------------------------------------------------------------------------
       
  1545 // Checks whether given event is one which generates visible character
       
  1546 // ---------------------------------------------------------------------------
       
  1547 //
       
  1548 TBool CNcsAifEditor::IsCharacterKey( const TKeyEvent& aKeyEvent ) const
       
  1549     {
       
  1550     FUNC_LOG;
       
  1551     TUint ctrlModifiers = EModifierLeftCtrl | EModifierRightCtrl | EModifierCtrl;
       
  1552     TBool ctrlEvent = aKeyEvent.iModifiers & ctrlModifiers;
       
  1553     TBool isAppKey = ( aKeyEvent.iScanCode >= EStdKeyApplication0) && (aKeyEvent.iScanCode <= EStdKeyKeyboardExtend);
       
  1554     return ( !ctrlEvent && !IsNavigationKey(aKeyEvent) && !isAppKey  );
       
  1555     }
       
  1556 
       
  1557 // ---------------------------------------------------------------------------
       
  1558 // Gets the count of substrings (in current text field) matching the aEntry's
       
  1559 // DisplayName (DN) and the count of matching (same DN) items in iArray. 
       
  1560 // ---------------------------------------------------------------------------
       
  1561 //
       
  1562 void CNcsAifEditor::GetMatchingEntryCountsL(  const CNcsAifEntry* aEntry,
       
  1563                                               TInt& aNrOfMatchesInText,
       
  1564                                               TInt& aNrOfMatchesInEntryArray )
       
  1565     {
       
  1566     aNrOfMatchesInText = 0;
       
  1567     aNrOfMatchesInEntryArray = 0;
       
  1568     TInt pos( 0 );
       
  1569     const TInt end_pos( TextLength() );
       
  1570 
       
  1571     // First a checking loop for finding the number of matching substrings
       
  1572     // (i.e., substrings that match the entry's displaystring) in current text
       
  1573     while ( pos < end_pos )
       
  1574         {
       
  1575         pos = FindTextL( &aEntry->DisplayString(), pos, 
       
  1576                          CEikEdwin::EFindCaseSensitive | 
       
  1577                          CEikEdwin::ENoBusyMessage );
       
  1578 
       
  1579         // No more matches for entry found => checking finished for this one 
       
  1580         if ( pos < 0 )
       
  1581             {
       
  1582             pos = end_pos; // ends the loop
       
  1583             }
       
  1584         // Match found => update counter
       
  1585         else
       
  1586             {
       
  1587             ++aNrOfMatchesInText;
       
  1588             // Move to next word
       
  1589             TInt len;
       
  1590             TInt startPos;
       
  1591             GetWordInfo( pos, startPos, len );
       
  1592             pos = startPos+len;
       
  1593             }
       
  1594         }
       
  1595 
       
  1596     // Secondly check the number of entries in entry array that match
       
  1597     // the given entry's displayname.
       
  1598     for ( TInt i = iArray.Count()-1; i >= 0; --i )
       
  1599         {
       
  1600         if ( !aEntry->DisplayString().Compare( iArray[i]->DisplayString() ) )
       
  1601             {
       
  1602             ++aNrOfMatchesInEntryArray;
       
  1603             }
       
  1604         }
       
  1605     }
       
  1606 
       
  1607 // End of File
       
  1608