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