diff -r 000000000000 -r 8466d47a6819 meetingrequest/mrgui/mrfieldbuilderpluginextension/src/cesmrncsaifeditor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meetingrequest/mrgui/mrfieldbuilderpluginextension/src/cesmrncsaifeditor.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,1318 @@ +/* +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: This file implements classes CESMRNcsAifEntry, CESMRNcsAifEditor. +* +*/ + +#include "emailtrace.h" +#include "cesmrncsaifeditor.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef FF_CMAIL_INTEGRATION +#include +#endif // FF_CMAIL_INTEGRATION + +#include "cesmrncsemailaddressobject.h" +#include "cesmrcontacthandler.h" +#include "esmrfieldbuilderdef.h" + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::NewL +// --------------------------------------------------------------------------- +// +CESMRNcsAifEntry* CESMRNcsAifEntry::NewL( + const CESMRNcsEmailAddressObject& addr, + TBool aDisplayFull ) + { + FUNC_LOG; + CESMRNcsAifEntry* self = new (ELeave) CESMRNcsAifEntry( aDisplayFull ); + CleanupStack::PushL(self); + self->ConstructL( addr ); + CleanupStack::Pop(self); + return self; + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::NewL +// --------------------------------------------------------------------------- +// +CESMRNcsAifEntry* CESMRNcsAifEntry::NewL( + const TDesC& aDn, + const TDesC& aEml, + TBool aDisplayFull ) + { + FUNC_LOG; + CESMRNcsAifEntry* self = new ( ELeave ) CESMRNcsAifEntry( aDisplayFull ); + CleanupStack::PushL(self); + self->ConstructL( aDn, aEml); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::~CESMRNcsAifEntry +// --------------------------------------------------------------------------- +// +CESMRNcsAifEntry::~CESMRNcsAifEntry() + { + FUNC_LOG; + delete iAddress; + delete iDisplayString; + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::CESMRNcsAifEntry +// --------------------------------------------------------------------------- +// +CESMRNcsAifEntry::CESMRNcsAifEntry( TBool aDisplayFull ) : + iDisplayFull( aDisplayFull ) + { + FUNC_LOG; + //do nothing + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::ConstructL +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEntry::ConstructL( const TDesC& aDn, const TDesC& aEml ) + { + FUNC_LOG; + iAddress = CESMRNcsEmailAddressObject::NewL( aDn, aEml ); + ConstructL(); + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::ConstructL +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEntry::ConstructL( const CESMRNcsEmailAddressObject& aAddress ) + { + FUNC_LOG; + iAddress = CESMRNcsEmailAddressObject::NewL( aAddress ); + ConstructL(); + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::ConstructL +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEntry::ConstructL() + { + FUNC_LOG; + SetDisplayStringL(); + } + +// --------------------------------------------------------------------------- +// CESMRNcsAifEntry::SetDisplayStringL +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEntry::SetDisplayStringL() + { + FUNC_LOG; + if ( iDisplayString ) + { + delete iDisplayString; + iDisplayString = NULL; + } + + const TDesC& dname = iAddress->DisplayName(); + const TDesC& email = iAddress->EmailAddress(); + + TInt dnameLength = dname.Length(); + TInt emailLength = email.Length(); + + TInt length; + if ( !iIsDup && !iDisplayFull ) + { + length = dnameLength > 0 ? dnameLength : emailLength; + length += 1; // ';' + + iDisplayString = HBufC::NewL( length ); + TPtr ptr = iDisplayString->Des(); + + ptr.Append( dname.Length() > 0 ? dname : email ); + ptr.Append( KAddressDelimeterSemiColon ); + } + else + { + // Display, Name ; + length = dnameLength + emailLength + 4; + + iDisplayString = HBufC::NewL( length ); + TPtr ptr = iDisplayString->Des(); + + ptr.Append( dname ); + _LIT(KLeft, " <"); + ptr.Append( KLeft ); + ptr.Append( email ); + _LIT(KRight, ">"); + ptr.Append( KRight ); + ptr.Append( KAddressDelimeterSemiColon ); + } + } + +// --------------------------------------------------------------------------- +// constructor/destructor +// --------------------------------------------------------------------------- +// +CESMRNcsAifEditor::CESMRNcsAifEditor( CESMRContactHandler& aContactHandler, HBufC* aDefaultText ) : + CESMRNcsEditor( aDefaultText ), iContactHandler( aContactHandler ) + { + FUNC_LOG; + SetEdwinObserver( this ); + } + +// --------------------------------------------------------------------------- +// constructor/destructor +// --------------------------------------------------------------------------- +// +CESMRNcsAifEditor::~CESMRNcsAifEditor() + { + FUNC_LOG; + iArray.ResetAndDestroy(); + iAddressArray.Reset(); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::CursorLineNumber() const +// ----------------------------------------------------------------------------- +// +TInt CESMRNcsAifEditor::CursorLineNumber() const + { + FUNC_LOG; + + TInt ret = iLayout->GetLineNumber( CursorPos() ); + ret++; + if( ret > KMaxAddressFieldLines ) + { + ret = KMaxAddressFieldLines; + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::LineCount() const +// ----------------------------------------------------------------------------- +// +TInt CESMRNcsAifEditor::LineCount() const + { + FUNC_LOG; + TInt lineCount = iLayout->GetLineNumber( TextLength() ); + lineCount++; + if( lineCount > KMaxAddressFieldLines ) + { + lineCount = KMaxAddressFieldLines; + } + return lineCount; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::OfferKeyEventL() +// ----------------------------------------------------------------------------- +// +TKeyResponse CESMRNcsAifEditor::OfferKeyEventL( const TKeyEvent& aKeyEvent, TEventCode aType ) + { + FUNC_LOG; + TKeyResponse ret = EKeyWasNotConsumed; + + // check if we are copying + if ( ret == EKeyWasNotConsumed ) + { + ret = CopyEntriesToClipboardL( aKeyEvent, aType ); + } + + // Check if we need to delete a contact + // We must do this before select sincey they + // key off of the same key code. + if ( ret == EKeyWasNotConsumed ) + { + ret = HandleContactDeletionL( aKeyEvent, aType ); + } + + // Check if we need to highlight a contact + if ( ret == EKeyWasNotConsumed ) + { + ret = SetEditorSelectionL( aKeyEvent, aType ); + } + + if ( ret == EKeyWasNotConsumed ) + { + ret = CESMRNcsEditor::OfferKeyEventL( aKeyEvent, aType ); + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::HandleEdwinEventL() +// This function gets called if a character is entered through the FEP. +// Otherwise the character entry is added through OfferKeyEvent +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::HandleEdwinEventL( CEikEdwin* /*aEdwin*/, TEdwinEvent aEventType ) + { + FUNC_LOG; + if ( aEventType == MEikEdwinObserver::EEventTextUpdate ) + { + HandleContactDeletionL(); + HandleTextUpdateL(); + } + else if ( aEventType == MEikEdwinObserver::EEventNavigation ) + { + HandleNavigationEventL(); + } + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::SetEditorSelectionL() +// ----------------------------------------------------------------------------- +// +TKeyResponse CESMRNcsAifEditor::SetEditorSelectionL( const TKeyEvent& aKeyEvent, TEventCode aType ) + { + FUNC_LOG; + TKeyResponse response = EKeyWasNotConsumed; + CESMRNcsAifEntry* entry = NULL; + TCursorSelection selection = Selection(); + + // Moving to a new line is a special case. + // We need to offer the key to the editor control first so it can + // move the cursor for us. Then we check if it's in an entry. + if ( aKeyEvent.iCode == EKeyUpArrow || aKeyEvent.iCode == EKeyDownArrow ) + { + response = CESMRNcsEditor::OfferKeyEventL( aKeyEvent,aType ); + if ( response == EKeyWasConsumed ) + { + // We're moving to a new line. + entry = GetEntryAt( CursorPos() ); + if ( entry ) + { + SetSelectionL( entry->iCursorPos, entry->iAnchorPos ); + } + } + } + // Check if the cursor is in any of the addresses + else if( aKeyEvent.iCode == EKeyLeftArrow || aKeyEvent.iCode == EKeyBackspace ) + { + // We're moving left, but haven't yet. + entry = GetEntryAt( CursorPos(), EDirectionLeft ); + if ( entry ) + { + if ( selection.Length() && aKeyEvent.iCode == EKeyLeftArrow) + { + // Adds or removes the entry from the current selection. + SetSelectionL( entry->LowerPos(), selection.iAnchorPos ); + response = EKeyWasConsumed; + } + else if ( !selection.Length() ) + { + SetSelectionL( entry->LowerPos(), entry->HigherPos() ); + response = EKeyWasConsumed; + } + } + } + else if( aKeyEvent.iCode == EKeyRightArrow || aKeyEvent.iCode == EKeyDelete ) + { + // We're moving right, but haven't yet. + entry = GetEntryAt( CursorPos(), EDirectionRight ); + if ( entry ) + { + if ( selection.Length() && aKeyEvent.iCode == EKeyRightArrow ) + { + // Adds or removes the entry form the current selection. + SetSelectionL( entry->HigherPos(), selection.iAnchorPos ); + response = EKeyWasConsumed; + } + else if ( !selection.Length() ) + { + SetSelectionL( entry->HigherPos(), entry->LowerPos() ); + response = EKeyWasConsumed; + } + } + } + + // Close the address popup if we handled the event + if ( response == EKeyWasConsumed ) + { + iAddressPopupList->ClosePopupContactListL(); + } + + return response; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::HandleContactDeletionL() +// ----------------------------------------------------------------------------- +// +TKeyResponse CESMRNcsAifEditor::HandleContactDeletionL( + const TKeyEvent& aKeyEvent, + TEventCode aType) + { + FUNC_LOG; + TKeyResponse response = EKeyWasNotConsumed; + if ( SelectionLength() && aType == EEventKey + && !IsNavigationKey( aKeyEvent ) ) + { + // Delete highlighted entries. + TCursorSelection selection = Selection(); + TBool entryDeleted = EFalse; + for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii ) + { + if ( iArray[ii]->LowerPos() >= selection.LowerPos() && + iArray[ii]->HigherPos() <= selection.HigherPos() ) + { + delete iArray[ii]; + iArray.Remove( ii ); + entryDeleted = ETrue; + } + } + + if ( entryDeleted ) + { + // Check that duplicate entries are correctly marked. + UpdateDuplicateEntryMarkings(); + + // Set the cursor after the entry before the ones we just deleted + CESMRNcsAifEntry* entry = NULL; + for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii ) + { + if ( iArray[ii]->HigherPos() <= selection.LowerPos() ) + { + entry = iArray[ii]; + break; + } + } + + ClearSelectionL(); + + RepositionEntriesL( entry ); + + // The key event is set consumed only on delete and backpace + // events, other events need to be forwarded to the editor. + if ( aKeyEvent.iCode == EKeyDelete || + aKeyEvent.iCode == EKeyBackspace ) + { + response = EKeyWasConsumed; + } + } + } + return response; + } + +// --------------------------------------------------------- +// CESMRNcsAifEditor::DoCharChangeL +// --------------------------------------------------------- +// +void CESMRNcsAifEditor::DoCharChangeL() + { + FUNC_LOG; + RecalculateEntryPositions(); + + TChar previousChar = CharAtPos( CursorPos() - 1 ); + TBool sentinel = ( previousChar == KSemiColon || + previousChar == KComma ); + if ( sentinel ) + { + // if comma was pressed we replace it with semicolon + if ( previousChar == KComma ) + { + CPlainText* text = Text(); + text->DeleteL( CursorPos() - 1, 1 ); + text->InsertL( CursorPos() - 1, KSemiColon ); + } + TBool check = ParseNewAddressL(); + } + UpdateAddressAutoCompletionL(); + } + +// --------------------------------------------------------- +// CESMRNcsAifEditor::CharAtPos +// --------------------------------------------------------- +// +TChar CESMRNcsAifEditor::CharAtPos( TInt aPos ) const + { + FUNC_LOG; + if ( aPos >= 0 && aPos < TextLength() ) + { + TBuf<1> buf; + Text()->Extract( buf, aPos, 1 ); + return buf[0]; + } + else + { + return 0; + } + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::SetAddressesL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::SetAddressesL( const RPointerArray& aAddresses ) + { + FUNC_LOG; + iArray.ResetAndDestroy(); + AppendAddressesL( aAddresses ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::AppendAddressesL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::AppendAddressesL( const RPointerArray& aAddresses ) + { + FUNC_LOG; + iArray.ReserveL( iArray.Count() + aAddresses.Count() ); + + CESMRNcsAifEntry* entry = NULL; + for (int i=0;iDisplayFull() ); + + int idx; + // Check for duplicate display names + for ( idx=0; idxIsSameDN( *entry ) ) + { + iArray[idx]->SetDup(); + entry->SetDup(); + } + } + + CleanupStack::PushL( entry ); + iArray.AppendL( entry ); + CleanupStack::Pop( entry ); + } + + RepositionEntriesL( entry ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetAddressesL() +// ----------------------------------------------------------------------------- +// +const RPointerArray& CESMRNcsAifEditor::GetAddressesL() + { + // Clear the existing array since it may be out of sync + iAddressArray.Reset(); + + for (int i=0;iAddress()); + } + + return iAddressArray; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetEntryAt() +// ----------------------------------------------------------------------------- +// +CESMRNcsAifEntry* CESMRNcsAifEditor::GetEntryAt( + TInt aPos, + TEntryDirection aDirection ) const + { + FUNC_LOG; + + TChar KSpace( ' ' ); + + for( TInt i = 0; i < iArray.Count(); i++ ) + { + CESMRNcsAifEntry* entry = iArray[i]; + if ( aDirection == EDirectionNone ) + { + // no direction, check if cursor is on entry + if ( entry->Includes( aPos ) ) + { + return entry; + } + } + else if ( aDirection == EDirectionRight ) + { + // direction to the righ. check if cursor is on entry or + // entry is immediately to the right of the cursor + if ( entry->Includes( aPos ) ) + { + return entry; + } + + if ( entry->Start() >= aPos && entry->Start() - aPos <= 1 && + CharAtPos( aPos ) == KSpace ) + { + return entry; + } + } + else if ( aDirection == EDirectionLeft ) + { + // direction to the left. decrease cursor by one and check if it + // is on entry or if entry is immediately to the left of the cursor + if ( entry->Includes( aPos - 1 ) ) + { + return entry; + } + + if ( aPos >= entry->End() && aPos - entry->End() <= 1 && + CharAtPos( aPos - 1 ) == KSpace ) + { + return entry; + } + } + } + return NULL; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::CheckAddressWhenFocusLostL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::CheckAddressWhenFocusLostL() + { + FUNC_LOG; + ParseNewAddressL(); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::ParseNewAddressL() +// ----------------------------------------------------------------------------- +// +TBool CESMRNcsAifEditor::ParseNewAddressL() + { + FUNC_LOG; + HBufC* text = GetNonEntryTextLC(); + + if ( !text ) + { + return false; + } + // check if there is a name for the email address + + // if name = NULL, it isn't in cleanupstack + HBufC* name = iContactHandler.GetLastSearchNameLC( *text ); + if ( name ) + { + AddAddressL( *name, *text, ETrue ); + CleanupStack::PopAndDestroy( name ); + } + else + { + AddAddressL(KNullDesC(),*text); + } + + CleanupStack::PopAndDestroy(text); + + return true; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetNonEntryTextL() +// This will extract any text that was entered that is not +// part of any existing entries +// ----------------------------------------------------------------------------- +// +HBufC* CESMRNcsAifEditor::GetNonEntryTextLC() const + { + FUNC_LOG; + // The user entered a new email address directly into the AIF + TInt pos = CursorPos(); + + // Check if the cursor is in an existing entry + for (int i=0;iIncludes(pos-1)) return NULL; + } + + // Pull the text to the left of the cursor up to the + // previous entry or the beginning of the doc + int idx = -1; + for (int i=0;iEnd() < pos) idx = i; + } + + // No entry before this text, pull to beginning of doc + int len, start; + if (idx == -1) + { + len = pos; + start = 0; + } + else + { + len = pos - iArray[idx]->End(); + start = iArray[idx]->End(); + } + + // The user could have moved the cursor into the new text. + // Pull the text to the right of the cursor up to the + // next entry or the end of the doc + for (idx=0;idxStart() >= pos) break; + } + + // No entry after this text, pull to end of doc + if (iArray.Count() == 0 || idx == iArray.Count()) + { + len += TextLength() - pos; + } + else + { + len += iArray[idx]->Start() - pos; + } + + // Extract the address text + HBufC* text = HBufC::NewLC(len); + TPtr ptr = text->Des(); + Text()->Extract(ptr,start,len); + + // Wipe out any delimiters + TChar semiColon(KSemiColon); + pos = ptr.Locate(semiColon); + if (pos != KErrNotFound) + ptr.Delete(pos,1); + + // Trim the string and add it to the entries list + ptr.Trim(); + + if (ptr.Length() == 0) + { + CleanupStack::PopAndDestroy(text); + return NULL; + } + + return text; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::CopyEntriesToClipBoardL +// ----------------------------------------------------------------------------- +// +TKeyResponse CESMRNcsAifEditor::CopyEntriesToClipboardL( + const TKeyEvent& aKeyEvent, + TEventCode aType ) + { + FUNC_LOG; + TKeyResponse ret = EKeyWasNotConsumed; + + const TInt KCopyKeyEventCode = 3; + const TInt KCutKeyEventCode = 24; + + // check that we are copying + TBool copyKeyEvent = ( aType == EEventKey && aKeyEvent.iCode == KCopyKeyEventCode && + aKeyEvent.iModifiers & EModifierCtrl && + aKeyEvent.iScanCode == EPtiKeyQwertyC ); + TBool cutKeyEvent = ( aType == EEventKey && aKeyEvent.iCode == KCutKeyEventCode && + aKeyEvent.iModifiers & EModifierCtrl && + aKeyEvent.iScanCode == EPtiKeyQwertyX ); + if ( copyKeyEvent || cutKeyEvent ) + { + RPointerArray entries; + CleanupClosePushL( entries ); + FindSelectedEntriesL( entries ); + if ( entries.Count() > 0 ) + { + CancelFepTransaction(); + HBufC* formattedText = GetFormattedAddressListLC( entries, EFalse ); + CopyToClipboardL( *formattedText ); + CleanupStack::PopAndDestroy( formattedText ); + + if ( !cutKeyEvent ) + { // cutting needs more handling + ret = EKeyWasConsumed; + } + } + CleanupStack::PopAndDestroy( &entries ); + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::FindSelectedEntriesL( ) +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::FindSelectedEntriesL( RPointerArray& aEntries ) + { + FUNC_LOG; + TCursorSelection selection = Selection(); + TInt count = iArray.Count(); + for ( TInt i = 0; i < iArray.Count(); i++ ) + { + CESMRNcsAifEntry* entry = iArray[i]; + if ( entry->Start() >= selection.LowerPos() && + entry->End() <= selection.HigherPos() ) + { + aEntries.AppendL( entry ); + } + } + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::EmailAddressIndexNameBySelection( ) +// ----------------------------------------------------------------------------- +// +const CESMRNcsEmailAddressObject* CESMRNcsAifEditor::EmailAddressObjectBySelection() const + + { + FUNC_LOG; + // Find the contact the cursor is in + const CESMRNcsAifEntry* aEntry = GetEntryAt(CursorPos()); + ASSERT(aEntry != NULL); + return &aEntry->Address(); + } + + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::AddAddressL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::AddAddressL( const CESMRNcsEmailAddressObject& aAddress ) + { + FUNC_LOG; + AddAddressL( CESMRNcsAifEntry::NewL( aAddress, aAddress.DisplayFull() ) ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::AddAddressL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::AddAddressL( + const TDesC& aDisplayName, + const TDesC& aEmail, + TBool aDisplayFull ) + { + FUNC_LOG; + AddAddressL( CESMRNcsAifEntry::NewL( aDisplayName, aEmail, aDisplayFull ) ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::AddAddressL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::AddAddressL( CESMRNcsAifEntry* aNewEntry ) + { + FUNC_LOG; + int idx; + // Check for duplicate display names + for (idx=0;idxIsSameDN(*aNewEntry)) + { + iArray[idx]->SetDup(); + aNewEntry->SetDup(); + } + } + + // Find the location where we need to insert the address + TInt pos = CursorPos(); + for (idx=0;idxStart()) break; + } + if (idx == iArray.Count()) + { + // Tack the address onto the end of the array + iArray.Append(aNewEntry); + } + else + { + iArray.Insert(aNewEntry,idx); + } + RepositionEntriesL( aNewEntry ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::RecalculateEntryPositions() +// The text has changed, so recalculate the positions of the items. +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::RecalculateEntryPositions() + { + FUNC_LOG; + + TInt pos(0); + TInt idx(0); + TInt error(0); + for (;idxDisplayString(), pos, + CEikEdwin::EFindCaseSensitive | CEikEdwin::ENoBusyMessage ) ); + ASSERT( KErrNone == error && KErrNotFound != pos ); + if(pos != iArray[idx]->Start()) + { + break; + } + pos += iArray[idx]->Length(); + } + + if(idx != iArray.Count()) + { + for (; idxSetPos( pos ); + pos++; // for whitespace + } + } + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::RepositionEntriesL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::RepositionEntriesL( const CESMRNcsAifEntry* aPosEntry ) + { + FUNC_LOG; + TInt pos = 0; + CESMRNcsAifEntry* aEntry; + for (int i=0;iSetPos( pos ); + pos++; // for whitespace + } + + // Reset the text + SetCursorPosL( 0, EFalse ); //In case the cursor pos is invalid + HBufC* text = NULL; + text = GetFormattedAddressListL( iArray ); + CleanupStack::PushL( text ); + + // text lenght plus one to ensure the formatting + // used is full, not band formatting. + SetUpperFullFormattingLength( text->Length() + 1 ); + + // The stupid control will reset all atributes if the text is blank ( font color, etc.). + if ( text->Length() == 0 ) + { + CleanupStack::PopAndDestroy( text ); + text = KEmptySpace().AllocL(); + CleanupStack::PushL( text ); + SetTextL( text ); + } + else + { + SetTextL( text ); + } + + CleanupStack::PopAndDestroy( text ); + HandleTextChangedL(); + + // Set the cursor at the end of the given entry + if ( !aPosEntry ) + { + SetCursorPosL( 0, EFalse ); + } + else + { + SetCursorPosL( aPosEntry->End(), EFalse ); + } + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetLookupTextLC() +// ----------------------------------------------------------------------------- +// +HBufC* CESMRNcsAifEditor::GetLookupTextLC() const + { + FUNC_LOG; + HBufC* text = GetTextInHBufL(); + + if (text == NULL) return NULL; + + CleanupStack::PushL( text ); + TPtr ptr( text->Des() ); + ptr = ptr.LeftTPtr( CursorPos() ); + TChar semiColon(KSemiColon); + TInt location = ptr.LocateReverse( semiColon ); + if( location != KErrNotFound ) + { + ptr = ptr.RightTPtr( ptr.Length() - location -1 ); + ptr.TrimLeft(); + } + return text; + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetFormattedAddressListLC() +// ----------------------------------------------------------------------------- +// +HBufC* CESMRNcsAifEditor::GetFormattedAddressListLC( + RPointerArray& aEntries, + TBool aDisplayList ) const + { + FUNC_LOG; + TInt length = CalculateAddressListLength( aEntries, aDisplayList ); + if( length <= 0 ) + { + return HBufC::NewLC(0); + } + + HBufC* buf = HBufC::NewLC( length ); + TPtr ptr = buf->Des(); + + TInt count = aEntries.Count(); + for( TInt i = 0; i < count; i++ ) + { + if ( aDisplayList ) + { + ptr.Append( aEntries[i]->DisplayString() ); + } + else + { + ptr.Append( aEntries[i]->Address().EmailAddress() ); + ptr.Append( KAddressDelimeterSemiColon ); + } + + // append whitespace, if not in the last entry + if ( i < count - 1 ) + { + ptr.Append( KEmptySpace ); + } + } + + return buf; + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::GetFormattedAddressListL() +// ----------------------------------------------------------------------------- +// +HBufC* CESMRNcsAifEditor::GetFormattedAddressListL( + RPointerArray& aEntries, + TBool aDisplayList ) const + { + FUNC_LOG; + HBufC* buf = GetFormattedAddressListLC( aEntries, aDisplayList ); + CleanupStack::Pop( buf ); + return buf; + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::CalculateAddressListLength() +// ----------------------------------------------------------------------------- +// +TInt CESMRNcsAifEditor::CalculateAddressListLength( + RPointerArray& aEntries, + TBool aDisplayList ) const + { + FUNC_LOG; + TInt length = 0; + TInt count = aEntries.Count(); + for( TInt i = 0; i < count; i++ ) + { + CESMRNcsAifEntry* aEntry = aEntries[ i ]; + if ( !aEntry ) continue; + if ( aDisplayList ) + { + length += aEntry->Length(); + } + else + { + // +1 is for semicolon + length += aEntry->Address().EmailAddress().Length() + 1; + } + } + + // add one white space after that so the format is + // aa(at)bb.com; cc(at)dd.com; ee(at)ff.com + if( count > 1 ) + { + // ( count - 1 ) we do need white space after the last address + length += count - 1 ; + } + + if( aEntries.Count() > 0 ) + { + length += 2; + } + + return length; + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::UpdateAddressAutoCompletionL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::UpdateAddressAutoCompletionL() + { + FUNC_LOG; + HBufC* text = GetNonEntryTextLC(); + + if( text ) + { + iAddressPopupList->UpdatePopupContactListL( *text, EFalse ); + CleanupStack::PopAndDestroy( text ); + } + else + { + iAddressPopupList->UpdatePopupContactListL( KNullDesC, EFalse ); + } + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::UpdateAddressAutoCompletionL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::UpdateAddressAutoCompletionL( + const TCursorSelection& aSelection ) + { + FUNC_LOG; + TInt length = aSelection.Length(); + HBufC* text = HBufC::NewLC( length ); + TPtr ptr = text->Des(); + Text()->Extract( ptr, aSelection.LowerPos(), length ); + ptr.Trim(); + if ( text->Length() ) + { + iAddressPopupList->UpdatePopupContactListL( *text, EFalse ); + } + else + { + iAddressPopupList->ClosePopupContactListL(); + } + CleanupStack::PopAndDestroy( text ); + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::UpdateAddressListAllL() +// ----------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::UpdateAddressListAllL() + { + FUNC_LOG; + iAddressPopupList->UpdatePopupContactListL( KNullDesC, ETrue ); + } + +void CESMRNcsAifEditor::UpdateDuplicateEntryMarkings() + { + FUNC_LOG; + const TInt entryCount = iArray.Count(); + for ( TInt ii = entryCount - 1; ii >= 0; --ii ) + { + TBool duplicateFound = EFalse; + for ( TInt jj = entryCount - 1; jj >= 0; --jj ) + { + if ( ii != jj && iArray[ii]->IsSameDN( *iArray[jj] ) ) + { + duplicateFound = ETrue; + iArray[jj]->SetDup( ETrue ); + } + } + iArray[ii]->SetDup( duplicateFound ); + } + } + +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::CopyToClipboardL +// ----------------------------------------------------------------------------- +void CESMRNcsAifEditor::CopyToClipboardL( const TDesC &aBuf ) + { + FUNC_LOG; + CClipboard* cb = CClipboard::NewForWritingLC( CCoeEnv::Static()->FsSession() ); + + cb->StreamDictionary().At( KClipboardUidTypePlainText ); + + CPlainText* plainText = CPlainText::NewL(); + CleanupStack::PushL( plainText ); + + plainText->InsertL( 0 , aBuf ); + + plainText->CopyToStoreL( cb->Store(), cb->StreamDictionary(), 0, plainText->DocumentLength() ); + + CleanupStack::PopAndDestroy( plainText ); + cb->CommitL(); + CleanupStack::PopAndDestroy( cb ); + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::HandleContactDeletionL +// ----------------------------------------------------------------------------- +void CESMRNcsAifEditor::HandleContactDeletionL() + { + FUNC_LOG; + const TInt count(iArray.Count()); + for (TInt i=count-1;i>=0;--i) + { + CESMRNcsAifEntry* entry = iArray[i]; + if ( FindTextL( &entry->DisplayString(), 0, 0 ) == KErrNotFound ) + { + iArray.Remove(i); + delete entry; + } + } + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::HandleTextUpdateL +// ----------------------------------------------------------------------------- +void CESMRNcsAifEditor::HandleTextUpdateL() + { + FUNC_LOG; + RecalculateEntryPositions(); + TCursorSelection textSelection = NonEntryTextAtPos( CursorPos() ); + if ( textSelection.Length() ) + { + // Check non-entry text for complete entries. + HandleTextUpdateL( textSelection ); + } + UpdateAddressAutoCompletionL( textSelection ); + } +// ----------------------------------------------------------------------------- +// CESMRNcsAifEditor::HandleTextUpdateL +// ----------------------------------------------------------------------------- +void CESMRNcsAifEditor::HandleTextUpdateL( TCursorSelection& aSelection ) + { + FUNC_LOG; + TInt firstCharacter = aSelection.LowerPos(); + TInt lastCharacter = aSelection.HigherPos(); + for ( TInt ii = firstCharacter; ii <= lastCharacter; ++ii ) + { + TChar character = CharAtPos( ii ); + if ( IsSentinel( character ) ) + { + if ( character == KComma ) + { + // Replace comma with semicolon + CPlainText* text = Text(); + text->DeleteL( ii, 1 ); + text->InsertL( ii, KSemiColon ); + } + + // Create new entry. + AddEntryL( firstCharacter, ii ); + TCursorSelection tmpSelection = NonEntryTextAtPos( CursorPos() ); + firstCharacter = tmpSelection.LowerPos(); + lastCharacter = tmpSelection.HigherPos(); + } + } + aSelection.SetSelection( lastCharacter, firstCharacter ); + + } + +// --------------------------------------------------------------------------- +// Handles navigation event. +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::HandleNavigationEventL() + { + FUNC_LOG; + // Close the contact popup when cursor is moved withing the field to make it less distracting. + // It's reopened when user types something. + iAddressPopupList->ClosePopupContactListL(); + } + +// --------------------------------------------------------------------------- +// Gets the range of non-entry text at the given position. +// --------------------------------------------------------------------------- +// +TCursorSelection CESMRNcsAifEditor::NonEntryTextAtPos( TUint aPosition ) const + { + FUNC_LOG; + TCursorSelection text( TextLength(), 0 ); + for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii ) + { + if ( iArray[ii]->Includes( aPosition - 1) ) + { + // Given position is included in existing entry + text.SetSelection( 0, 0 ); + break; + } + else if ( iArray[ii]->LowerPos() >= aPosition ) + { + // Found entry after the given position + text.iCursorPos = iArray[ii]->LowerPos(); + } + else if ( iArray[ii]->HigherPos() < aPosition ) + { + // Found first entry before given position + text.iAnchorPos = iArray[ii]->HigherPos(); + break; + } + } + return text; + } + +// --------------------------------------------------------------------------- +// Gets the range of text immediatelly before given position that does not +// belong to any entry. +// --------------------------------------------------------------------------- +// +TCursorSelection CESMRNcsAifEditor::NonEntryTextBeforePos( TUint aPosition ) const + { + FUNC_LOG; + TCursorSelection text( aPosition, 0 ); + for ( TInt ii = iArray.Count() - 1; ii >= 0; --ii ) + { + if ( iArray[ii]->Includes( aPosition - 1 ) ) + { + // Given position is included in existing entry + text.SetSelection( 0, 0 ); + break; + } + else if ( iArray[ii]->HigherPos() < aPosition ) + { + // Found first existing entry before given position + text.SetSelection( aPosition, iArray[ii]->HigherPos() ); + break; + } + } + return text; + } + +// --------------------------------------------------------------------------- +// Checks whether given character is considered as sentinel. +// --------------------------------------------------------------------------- +// +TBool CESMRNcsAifEditor::IsSentinel( TChar aCharacter ) const + { + FUNC_LOG; + return ( aCharacter == KSemiColon || + aCharacter == KComma ); + } + +// --------------------------------------------------------------------------- +// Checks whether given event is considered as navigation event. +// --------------------------------------------------------------------------- +// +TBool CESMRNcsAifEditor::IsNavigationKey( const TKeyEvent& aKeyEvent ) const + { + FUNC_LOG; + return ( aKeyEvent.iCode == EKeyLeftArrow || + aKeyEvent.iCode == EKeyRightArrow || + aKeyEvent.iCode == EKeyUpArrow || + aKeyEvent.iCode == EKeyDownArrow ); + } + +// --------------------------------------------------------------------------- +// Creates new entry from the specified section of the the input field. +// --------------------------------------------------------------------------- +// +void CESMRNcsAifEditor::AddEntryL( TInt aStart, TInt aEnd ) + { + FUNC_LOG; + // Get the text for the entry (excluding the delimiter) + TInt length = aEnd - aStart; + HBufC* text = HBufC::NewLC( length ); + TPtr ptr = text->Des(); + Text()->Extract( ptr, aStart, length ); + ptr.Trim(); + if ( text->Length() ) + { + AddAddressL( KNullDesC(), *text ); + } + CleanupStack::PopAndDestroy( text ); + } +// End of File +