|
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 |