emailuis/nmailuiwidgets/src/nmrecipientlineedit.cpp
changeset 74 6c59112cfd31
parent 68 83cc6bae1de8
child 76 38bf5461e270
equal deleted inserted replaced
69:4e54af54a4a1 74:6c59112cfd31
     9 * Initial Contributors:
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    10 * Nokia Corporation - initial contribution.
    11 *
    11 *
    12 * Contributors:
    12 * Contributors:
    13 *
    13 *
    14 * Description: nmrecipientlineedit.cpp
    14 * Description: implementation of recipient field (to, cc, bcc) line editor
    15 * 
    15 *
    16 */
    16 */
    17 
    17 
    18 #include "nmailuiwidgetsheaders.h"
    18 #include "nmailuiwidgetsheaders.h"
    19 
    19 
    20 static const QString Semicolon(";");
    20 static const QString NmRecipientLineEditSemicolon(";");
    21 static const QString Delimiter("; ");
    21 static const QString NmRecipientLineEditDelimiter("; ");
    22 static const QRegExp CommaOrSemicolon("[,;]");
    22 static const QRegExp NmRecipientLineEditCommaOrSemicolon("[,;]");
    23 
    23 
    24 
    24 static const int NmRecipientLineEditFadedAlpha(125);
       
    25 
       
    26 static const int NmRecipientLineEditForegroundZValue(200);
       
    27 static const int NmRecipientLineEditBackgroundZValue(0);
       
    28 
       
    29 static const QString FILE_PATH_WIDGETML = ":nmrecipientlineedit.widgetml";
       
    30 static const QString FILE_PATH_CSS = ":nmrecipientlineedit.css";
       
    31 static const QString FILE_PATH_AUTOFILL_DOCML = ":nmautofilllistview.docml";
       
    32 static const QString FILE_PATH_AUTOFILLITEM_WIDGETML = ":nmautofilllistviewitem.widgetml";
       
    33 static const QString FILE_PATH_AUTOFILLITEM_CSS = ":nmautofilllistviewitem.css";
    25 /*!
    34 /*!
    26    Constructor
    35    Constructor
    27 */
    36 */
    28 NmRecipientLineEdit::NmRecipientLineEdit(QGraphicsItem *parent) 
    37 NmRecipientLineEdit::NmRecipientLineEdit(QGraphicsItem *parent)
    29     : NmHtmlLineEdit(parent),
    38     : NmHtmlLineEdit(parent),
    30     mNeedToGenerateEmailAddressList(true)
    39     mNeedToGenerateEmailAddressList(true),
    31 {
    40     mContactHistoryModel(NULL),
    32     NM_FUNCTION;
    41     mAutoFillPopup(NULL),
    33     
    42     mAutofillListView(NULL),
       
    43     mAutofillListViewItem(NULL),
       
    44     mPopupBackground(NULL)
       
    45 {
       
    46     NM_FUNCTION;
       
    47 
       
    48     HbStyleLoader::registerFilePath(FILE_PATH_WIDGETML);
       
    49     HbStyleLoader::registerFilePath(FILE_PATH_CSS);
       
    50     HbStyleLoader::registerFilePath(FILE_PATH_AUTOFILLITEM_WIDGETML);
       
    51     HbStyleLoader::registerFilePath(FILE_PATH_AUTOFILLITEM_CSS);
       
    52 
       
    53     createAutofillComponents();
       
    54 
    34     connect(this, SIGNAL(textChanged(QString)), this, SLOT(handleTextChanged(QString)));
    55     connect(this, SIGNAL(textChanged(QString)), this, SLOT(handleTextChanged(QString)));
    35 }
    56 }
    36 
    57 
    37 
       
    38 /*!
    58 /*!
    39    Destructor
    59    Destructor
    40 */
    60 */
    41 NmRecipientLineEdit::~NmRecipientLineEdit()
    61 NmRecipientLineEdit::~NmRecipientLineEdit()
    42 {
    62 {
    43     NM_FUNCTION;
    63     NM_FUNCTION;
    44 }
    64     delete mPopupBackground;
    45 
    65     delete mContactHistoryModel;
       
    66     delete mAutofillListView;
       
    67 
       
    68     HbStyleLoader::unregisterFilePath(FILE_PATH_WIDGETML);
       
    69     HbStyleLoader::unregisterFilePath(FILE_PATH_CSS);
       
    70     HbStyleLoader::unregisterFilePath(FILE_PATH_AUTOFILLITEM_WIDGETML);
       
    71     HbStyleLoader::unregisterFilePath(FILE_PATH_AUTOFILLITEM_CSS);
       
    72 }
    46 
    73 
    47 /*!
    74 /*!
    48    Get the emailaddress list generated from the content of the lineedit.
    75    Get the emailaddress list generated from the content of the lineedit.
    49 */
    76 */
    50 QList<NmAddress> NmRecipientLineEdit::emailAddressList()
    77 QList<NmAddress> NmRecipientLineEdit::emailAddressList()
    51 {
    78 {
    52     NM_FUNCTION;
    79     NM_FUNCTION;
    53     
    80 
    54     if (mNeedToGenerateEmailAddressList) {
    81     if (mNeedToGenerateEmailAddressList) {
    55         // Empty mEmailAddressList.
    82         // Empty mEmailAddressList.
    56         mEmailAddressList.clear();
    83         mEmailAddressList.clear();
    57         // Generate mEmailAddressList from the lineedit content.
    84         // Generate mEmailAddressList from the lineedit content.
    58         generateEmailAddressList();					
    85         generateEmailAddressList();
    59         mNeedToGenerateEmailAddressList = false;
    86         mNeedToGenerateEmailAddressList = false;
    60     }
    87     }
    61 
    88 
    62     return mEmailAddressList;	
    89     return mEmailAddressList;
    63 }
    90 }
    64 
    91 
    65 
    92 /*!
    66 #ifdef Q_OS_SYMBIAN
    93    This Slot appends the selected contacts to the end of the lineedit content.
    67 /*!
       
    68    This Slot appends the selected contacts to the end of the lineedit content.    
       
    69 */
    94 */
    70 void NmRecipientLineEdit::addSelectedContacts(const QVariant &selectedContacts)
    95 void NmRecipientLineEdit::addSelectedContacts(const QVariant &selectedContacts)
    71 {
    96 {
    72     NM_FUNCTION;
    97     NM_FUNCTION;
    73     
    98 
    74     // If user selected contact
    99     // If user selected contact
    75     if (!selectedContacts.isNull()) {        
   100     if (!selectedContacts.isNull()) {
    76 
   101 
    77         // If the lineedit is not empty and if there is no ";" or "; " at the end,
   102         // If the lineedit is not empty and if there is no ";" or "; " at the end,
    78         // add a delimiter("; ") at the end.
   103         // add a delimiter("; ") at the end.
    79         if (this->text().length() != 0 && !(this->text().endsWith(Semicolon)) && 
   104         if (text().length() != 0 && !(text().endsWith(NmRecipientLineEditSemicolon)) &&
    80             !(this->text().endsWith(Delimiter))){
   105             !(text().endsWith(NmRecipientLineEditDelimiter))){
    81             
   106 
    82             // Move cursor to the end of the lineedit.
   107             // Move cursor to the end of the lineedit.
    83             this->setCursorPosition(this->text().length());       
   108             setCursorPosition(text().length());
    84             QTextCursor textCursor(this->textCursor());
   109             QTextCursor textCursor(this->textCursor());
    85             // Append delimiter("; ") to the end of the lineedit
   110             // Append delimiter("; ") to the end of the lineedit
    86             textCursor.insertText(Delimiter);
   111             textCursor.insertText(NmRecipientLineEditDelimiter);
    87         }
   112         }
    88         
   113 
    89         CntServicesContactList contactList = qVariantValue<CntServicesContactList>(selectedContacts);
   114         CntServicesContactList contactList = qVariantValue<CntServicesContactList>(selectedContacts);
    90 
   115 
    91         // Loop through all the selected contacts.
   116         // Loop through all the selected contacts.
    92         for (int i = 0; i < contactList.count(); ++i) {
   117         for (int i = 0; i < contactList.count(); ++i) {
    93             QString contactName = contactList[i].mDisplayName;
   118             QString contactName = contactList[i].mDisplayName;
    94             QString contactEmailAddress = contactList[i].mEmailAddress;
   119             QString contactEmailAddress = contactList[i].mEmailAddress;
    95             
   120 
    96             // If this contact has no name, use it's emailaddress as the display name
   121             // If this contact has no name, use it's emailaddress as the display name
    97             if(contactName.isEmpty()) {	
   122             if (contactName.isEmpty()) {
    98                 // Move cursor to the end of the lineedit.
   123                 // Move cursor to the end of the lineedit.
    99                 this->setCursorPosition(this->text().length());       
   124                 setCursorPosition(text().length());
   100                 QTextCursor textCursor(this->textCursor());
   125                 insertContactText(contactEmailAddress);
   101                 // Append contactEmailAddress to the end of the lineedit
       
   102                 textCursor.insertText(contactEmailAddress);
       
   103             }
   126             }
   104             // If this contact has name, use the name as the display name
   127             // If this contact has name, use the name as the display name
   105             else {
   128             else {
   106                 // Handle a rare case: there are contacts has same name but different emailaddress.
   129                 // Handle a rare case: there are contacts has same name but different emailaddress.
   107                 for (int i = 0; i != mRecipientsAddedFromContacts.count(); ++i) {
   130                 for (int i = 0; i != mRecipientsAddedFromContacts.count(); ++i) {
   111                         contactName.append("<");
   134                         contactName.append("<");
   112                         contactName.append(contactEmailAddress);
   135                         contactName.append(contactEmailAddress);
   113                         contactName.append(">");
   136                         contactName.append(">");
   114                     }
   137                     }
   115                 }
   138                 }
   116                 
   139 
   117                 // Move cursor to the end of the lineedit.
   140                 // Move cursor to the end of the lineedit.
   118                 this->setCursorPosition(this->text().length());       
   141                 setCursorPosition(text().length());
   119                 QTextCursor textCursor(this->textCursor());
   142                 insertContactText(contactName);
   120                 // Append contactName to the end of the lineedit
   143             }
   121                 textCursor.insertText(contactName);
   144 
   122             }
   145             // Form the contact into NmAddress format.
   123                 
       
   124             QTextCursor textCursor(this->textCursor());
       
   125             // Append delimiter("; ")
       
   126             textCursor.insertText(Delimiter);
       
   127             
       
   128             // Form the contact into Qmail NmAddress format.
       
   129             NmAddress contact;
   146             NmAddress contact;
   130             contact.setAddress(contactEmailAddress);
   147             contact.setAddress(contactEmailAddress);
   131             contact.setDisplayName(contactName);
   148             contact.setDisplayName(contactName);
   132             
   149 
   133             // Add this NmAddress formated contact into mRecipientsAddedFromContacts.
   150             // Add this NmAddress formated contact into mRecipientsAddedFromContacts.
   134             mRecipientsAddedFromContacts.append(contact);
   151             mRecipientsAddedFromContacts.append(contact);
   135         } 
   152         }
   136     }
   153     }
   137     else {
   154     else {
   138         //Request returned NULL 
   155         //Request returned NULL
   139         NM_COMMENT("ContactsPicker request returned NULL.");
   156         NM_COMMENT("ContactsPicker request returned NULL.");
   140     }
   157     }
   141         
       
   142 }
   158 }
   143 
   159 
   144 Q_IMPLEMENT_USER_METATYPE(CntServicesContact)
   160 Q_IMPLEMENT_USER_METATYPE(CntServicesContact)
   145 Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList)
   161 Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList)
   146 #endif   // Q_OS_SYMBIAN
   162 
   147 
   163 /*!
   148 
   164    keyPressEvent handles different keypress events, and reacts to them
   149 /*!
       
   150    keyPressEvent handles replacing user inputs "," or ";" from physical keyboard with "; "
       
   151    P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard,
       
   152    inputMethodEvent method handles user inputs "," or ";" from virtual keyboard.
       
   153 */
   165 */
   154 void NmRecipientLineEdit::keyPressEvent(QKeyEvent *keyEvent)
   166 void NmRecipientLineEdit::keyPressEvent(QKeyEvent *keyEvent)
   155 {
   167 {
   156     NM_FUNCTION;
   168     NM_FUNCTION;
   157     
   169 
   158 	bool eventHandled = false;
       
   159 	
       
   160     if (keyEvent) {
   170     if (keyEvent) {
   161         switch (keyEvent->key()) {    
   171         switch (keyEvent->key()) {
   162         case Qt::Key_Comma:
   172         case Qt::Key_Comma:
   163         case Qt::Key_Semicolon:
   173         case Qt::Key_Semicolon:
   164             {
   174             keyPressEventSemicolon(keyEvent);
   165                 QString textBeforeCursor = (this->text()).left(this->cursorPosition());
   175             break;
   166                 
   176             
   167                 // No action when the lineedit is empty or cursor is after a Delimiter("; ") 
   177         case Qt::Key_Backspace:
   168                 // or a Semicolon (";").
   178         case Qt::Key_Delete:
   169                 if ((this->text()).isEmpty() || textBeforeCursor.endsWith(Delimiter)
   179             keyPressEventDelete(keyEvent);
   170                     || textBeforeCursor.endsWith(Semicolon)) {
   180             break;
   171                     keyEvent->ignore();
   181             
   172                     eventHandled = true;
   182         case Qt::Key_Left:
   173                 }
   183             keyPressEventLeft(keyEvent);
   174                 else {
   184             break;
   175                     // Generate custom keyevent for Delimiter("; ") and 
   185 
   176                     // forward to the base class to handle.
   186         case Qt::Key_Right:
   177                     QKeyEvent delimiterKeyEvent(keyEvent->type(), keyEvent->key(),
   187             keyPressEventRight(keyEvent);
   178                                                 keyEvent->modifiers(), Delimiter);
       
   179                     NmHtmlLineEdit::keyPressEvent(&delimiterKeyEvent);
       
   180                     eventHandled = true;
       
   181                 }
       
   182             }
       
   183             break;
   188             break;
   184 
   189 
   185         default:
   190         default:
   186             NmHtmlLineEdit::keyPressEvent(keyEvent);
   191             NmHtmlLineEdit::keyPressEvent(keyEvent);
   187             eventHandled = true;
   192             break;
   188             break;      
   193         } // switch
   189         }
   194     keyEvent->accept();
   190     }
   195     }
   191     
   196 }
   192     // If event is not handled, forward to the base class to handle.
   197 
   193     if (!eventHandled) {
   198 /*!
   194         NmHtmlLineEdit::keyPressEvent(keyEvent);
   199  * subroutine of keyPressEvent that handles semicolon and comma key presses
   195     }
   200  */
   196 }
   201 void NmRecipientLineEdit::keyPressEventSemicolon(QKeyEvent *event)
   197 
   202 {
       
   203     NM_FUNCTION;
       
   204     QString textBeforeCursor = (text()).left(cursorPosition());
       
   205 
       
   206     // No action when the lineedit is empty or cursor is after a Delimiter("; ")
       
   207     // or a Semicolon (";").
       
   208     if ((text()).isEmpty() || textBeforeCursor.endsWith(NmRecipientLineEditDelimiter)
       
   209         || textBeforeCursor.endsWith(NmRecipientLineEditSemicolon)) {
       
   210         event->ignore();
       
   211     }
       
   212     else {
       
   213         // Generate custom keyevent for Delimiter("; ") and
       
   214         // forward to the base class to handle.
       
   215         QKeyEvent delimiterKeyEvent(event->type(), event->key(),
       
   216                                     event->modifiers(), NmRecipientLineEditDelimiter);
       
   217         NmHtmlLineEdit::keyPressEvent(&delimiterKeyEvent);
       
   218     }
       
   219 }
       
   220 
       
   221 /*!
       
   222  * subroutine of keyPressEvent that handles delete and backspace key presses
       
   223  */
       
   224 void NmRecipientLineEdit::keyPressEventDelete(QKeyEvent *event)
       
   225 {
       
   226     NM_FUNCTION;
       
   227     int pos = cursorPosition();
       
   228 
       
   229     // 1) if selection exists, delete it
       
   230     if (hasSelectedText()) {
       
   231         // if already selected delete it
       
   232         disconnect(this, SIGNAL(textChanged(QString)),
       
   233                 this, SLOT(handleTextChanged(QString)));
       
   234         QKeyEvent eve(event->type(), Qt::Key_Delete, Qt::NoModifier);
       
   235         HbLineEdit::keyPressEvent(&eve);
       
   236         connect(this, SIGNAL(textChanged(QString)),
       
   237                 this, SLOT(handleTextChanged(QString)));
       
   238         setCursorPosition(text().length());
       
   239         handleTextChanged(text());
       
   240     } else { // no selection..
       
   241         // peek if earlier chars are underlined
       
   242         setCursorPosition(pos-2);
       
   243         bool isContact(textCursor().charFormat().fontUnderline());
       
   244         setCursorPosition(pos);
       
   245         if (isContact) {
       
   246             // contact
       
   247             setCursorPosition(pos-3);
       
   248             setHighlight(pos-3); // creates a selection for the current contact
       
   249         } else {
       
   250             // plain text
       
   251             HbLineEdit::keyPressEvent(event);
       
   252         }
       
   253     }
       
   254 }
       
   255 
       
   256 /*!
       
   257  * subroutine of keyPressEvent that handles left key presses
       
   258  */
       
   259 void NmRecipientLineEdit::keyPressEventLeft(QKeyEvent *event)
       
   260 {
       
   261     NM_FUNCTION;
       
   262     //look ahead left.
       
   263     int pos = cursorPosition();
       
   264     QString text = this->text();
       
   265     text = text.left(pos);
       
   266 
       
   267     //look for next seperator while going left.
       
   268     int semicolonPos = text.lastIndexOf(NmRecipientLineEditSemicolon);
       
   269     bool selectedText = hasSelectedText();
       
   270 
       
   271     if (selectedText) {
       
   272         int selectionStart = textCursor().selectionStart();
       
   273         if (selectionStart>=2) {
       
   274             setCursorPosition(selectionStart-2);
       
   275         }
       
   276         else {
       
   277             setCursorPosition(0);
       
   278         }
       
   279         textCursor().clearSelection();
       
   280     }
       
   281     else { // not selected
       
   282 
       
   283         setCursorPosition(pos-2);
       
   284         bool isContact = textCursor().charFormat().fontUnderline();
       
   285         setCursorPosition(pos);
       
   286 
       
   287         if (isContact) {
       
   288             setHighlight(pos-3);
       
   289         }
       
   290         else {
       
   291             if (pos-2  == semicolonPos) {
       
   292                 setCursorPosition(pos-1); // jump over one extra char
       
   293             }
       
   294             HbLineEdit::keyPressEvent(event);
       
   295         }
       
   296     }
       
   297 }
       
   298 
       
   299 /*!
       
   300  * subroutine of keyPressEvent that handles right key presses
       
   301  */
       
   302 void NmRecipientLineEdit::keyPressEventRight(QKeyEvent *event)
       
   303 {
       
   304     NM_FUNCTION;
       
   305     bool selectedText = hasSelectedText();
       
   306 
       
   307     if (selectedText) {
       
   308         int selectionEnd = textCursor().selectionEnd();
       
   309         setCursorPosition(selectionEnd+1);
       
   310         textCursor().clearSelection();
       
   311     }
       
   312     else {
       
   313         int pos = cursorPosition();
       
   314 
       
   315         //look ahead
       
   316         setCursorPosition(pos+3);
       
   317         bool isContact = textCursor().charFormat().fontUnderline();
       
   318         setCursorPosition(pos);
       
   319 
       
   320         if (isContact) {
       
   321             setHighlight(pos+3);
       
   322         }
       
   323         else {
       
   324             int nextSemicolon = text().indexOf(NmRecipientLineEditSemicolon,pos);
       
   325             if (nextSemicolon==pos) {
       
   326                 setCursorPosition(pos+1); // jump over one extra char
       
   327             }
       
   328         HbLineEdit::keyPressEvent(event);
       
   329         }
       
   330     }
       
   331 }
   198 
   332 
   199 /*!
   333 /*!
   200    inputMethodEvent handles replacing user inputs "," or ";" from virtual keyboard with "; ".
   334    inputMethodEvent handles replacing user inputs "," or ";" from virtual keyboard with "; ".
   201    P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard
   335    P.S. keyPressEvent can only catch QKeyEvent "," or ";" typed from physical keyboard
   202 */
   336 */
   203 void NmRecipientLineEdit::inputMethodEvent(QInputMethodEvent *event)
   337 void NmRecipientLineEdit::inputMethodEvent(QInputMethodEvent *event)
   204 {
   338 {
   205     NM_FUNCTION;
   339     NM_FUNCTION;
   206     
   340 
   207 	bool eventHandled = false;
   341 	bool eventHandled(false);
   208 	
   342 
   209     if (event) {
   343     if (event) {
   210         QString eventText = event->commitString();
   344         QString eventText = event->commitString();
   211 
   345 
   212         if (!eventText.isEmpty() || event->replacementLength()) {
   346         if (!eventText.isEmpty() || event->replacementLength()) {
   213             // If typed charater from virtual keyboard is "," or ";"
   347             // If typed charater from virtual keyboard is "," or ";"
   214             if (eventText.contains(CommaOrSemicolon)) {
   348             if (eventText.contains(NmRecipientLineEditCommaOrSemicolon)) {
   215                 QString textBeforeCursor = (this->text()).left(this->cursorPosition());
   349                 QString textBeforeCursor = text().left(cursorPosition());
   216 				
   350 
   217                 // No action when the lineedit is empty or cursor is after a Delimiter("; ") 
   351                 // No action when the lineedit is empty or cursor is after a Delimiter("; ")
   218                 // or Semicolon (";").
   352                 // or Semicolon (";").
   219                 if ((this->text()).isEmpty() || textBeforeCursor.endsWith(Delimiter)
   353                 if (text().isEmpty() || textBeforeCursor.endsWith(NmRecipientLineEditDelimiter) || textBeforeCursor.endsWith(NmRecipientLineEditSemicolon)) {
   220                     || textBeforeCursor.endsWith(Semicolon)) {
       
   221                     event->ignore();
   354                     event->ignore();
   222                     eventHandled = true;
   355                     eventHandled = true;
   223                 }
   356                 }
   224                 else {
   357                 else {
   225                     // Modify event with Delimiter("; ") and forward to the base class to handle.
   358                     // Modify event with Delimiter("; ") and forward to the base class to handle.
   226                     event->setCommitString(Delimiter, event->replacementStart(),
   359                     event->setCommitString(NmRecipientLineEditDelimiter, event->replacementStart(),
   227                                            event->replacementLength()); 
   360                                            event->replacementLength());
   228                     NmHtmlLineEdit::inputMethodEvent(event);
   361                     NmHtmlLineEdit::inputMethodEvent(event);
   229                     eventHandled = true;
   362                     eventHandled = true;
   230                 }
   363                 }
   231             }
   364             }
   232         }
   365         }
   236     if (!eventHandled) {
   369     if (!eventHandled) {
   237         NmHtmlLineEdit::inputMethodEvent(event);
   370         NmHtmlLineEdit::inputMethodEvent(event);
   238     }
   371     }
   239 }
   372 }
   240 
   373 
   241  
   374 /*!
       
   375  signal received from user screen input
       
   376  */
       
   377 void NmRecipientLineEdit::gestureEvent(QGestureEvent* event)
       
   378 {
       
   379     //passing gesture event to base class.
       
   380     HbLineEdit::gestureEvent(event);
       
   381 
       
   382     if (HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture))) {
       
   383         //capturing gesture position, and map to local co-ordinates.
       
   384         QPointF pos = mapFromScene(tap->scenePosition());
       
   385 
       
   386         switch (tap->state()) {
       
   387         case Qt::GestureFinished:
       
   388             if (HbTapGesture::Tap == tap->tapStyleHint()) {
       
   389                 handleTap();
       
   390             }
       
   391             break;
       
   392         default:
       
   393             break;
       
   394         }
       
   395         event->accept();
       
   396     }
       
   397     else {
       
   398         event->ignore();
       
   399     }
       
   400 }
       
   401 
       
   402 /*!
       
   403  user has tapped the recipient field on the screen
       
   404  */
       
   405 void NmRecipientLineEdit::handleTap()
       
   406 {
       
   407     int currentPos = cursorPosition();
       
   408     QString txt = text();
       
   409 
       
   410     QString leftTxt = txt.left(currentPos+2);
       
   411     int previousSemicolonIndex = leftTxt.lastIndexOf(NmRecipientLineEditSemicolon,currentPos);
       
   412     if ((currentPos>0) &&
       
   413        (currentPos==previousSemicolonIndex || currentPos==previousSemicolonIndex+1)) {
       
   414         //pressed just on seperator
       
   415         setCursorPosition(previousSemicolonIndex+2);
       
   416     }
       
   417     else
       
   418     {
       
   419         // pressed in middle of an address
       
   420         setCursorPosition(currentPos);
       
   421         if (textCursor().charFormat().fontUnderline()) {
       
   422             // This entry is a "contact"
       
   423             setHighlight(currentPos);
       
   424         }
       
   425     }
       
   426     update();
       
   427 }
       
   428 
   242 /*!
   429 /*!
   243    Generate a list of all the email addresses from the content of the lineedit.
   430    Generate a list of all the email addresses from the content of the lineedit.
   244 */
   431 */
   245 void NmRecipientLineEdit::generateEmailAddressList()
   432 void NmRecipientLineEdit::generateEmailAddressList()
   246 {   
   433 {
   247     NM_FUNCTION;
   434     NM_FUNCTION;
   248     
   435 
   249     // Remove whitespace from the start and the end of the lineedit content. 
   436     // Remove whitespace from the start and the end of the lineedit content.
   250     QString contentOfLineedit = (this->text()).trimmed();
   437     QString contentOfLineedit = text().trimmed();
   251     
   438 
   252     // Split the lineedit content by semicolon(";").
   439     // Split the lineedit content by semicolon(";").
   253     QStringList itemsOfLineeditContent = contentOfLineedit.split(Semicolon, QString::SkipEmptyParts);
   440     QStringList itemsOfLineeditContent = contentOfLineedit.split(NmRecipientLineEditSemicolon, QString::SkipEmptyParts);
   254         
   441 
   255     // Loop through all the items of the lineedit content.
   442     // Loop through all the items of the lineedit content.
   256     for (int i = 0; i != itemsOfLineeditContent.count(); ++i) {
   443     for (int i = 0; i != itemsOfLineeditContent.count(); ++i) {
   257         // Remove whitespace from the start and the end of the item.
   444         // Remove whitespace from the start and the end of the item.
   258         QString itemInLineedit = itemsOfLineeditContent.at(i).trimmed();
   445         QString itemInLineedit = itemsOfLineeditContent.at(i).trimmed();
   259 
   446 
   260         // Get the count of the recipients added from Contacts.
   447         // Get the count of the recipients added from Contacts.
   261         int countOfRecipientsAddedFromContacts = mRecipientsAddedFromContacts.count();
   448         int countOfRecipientsAddedFromContacts = mRecipientsAddedFromContacts.count();
   262         
   449 
   263         // If there is recipient added from Contacts.
   450         // If there is recipient added from Contacts.
   264         if (countOfRecipientsAddedFromContacts > 0) {
   451         if (countOfRecipientsAddedFromContacts > 0) {
   265             QStringList listOfAddedContactsName;
   452             QStringList listOfAddedContactsName;
   266             QStringList listOfAddedContactsAddress;
   453             QStringList listOfAddedContactsAddress;
   267             
   454 
   268             // Loop through all the recipients added from Contacts.
   455             // Loop through all the recipients added from Contacts.
   269             for (int j = 0; j != countOfRecipientsAddedFromContacts; ++j) {
   456             for (int j = 0; j != countOfRecipientsAddedFromContacts; ++j) {
   270                 NmAddress contact = mRecipientsAddedFromContacts.at(j);          
   457                 NmAddress contact = mRecipientsAddedFromContacts.at(j);
   271                 listOfAddedContactsName.append(contact.displayName());
   458                 listOfAddedContactsName.append(contact.displayName());
   272                 listOfAddedContactsAddress.append(contact.address());
   459                 listOfAddedContactsAddress.append(contact.address());
   273             }
   460             }
   274                 
   461 
   275             int indexInAddedContactsName = listOfAddedContactsName.indexOf(itemInLineedit);
   462             int indexInAddedContactsName = listOfAddedContactsName.indexOf(itemInLineedit);
   276             int indexInAddedContactsAddress = listOfAddedContactsAddress.indexOf(itemInLineedit);
   463             int indexInAddedContactsAddress = listOfAddedContactsAddress.indexOf(itemInLineedit);
   277             
   464 
   278             // If this itemInLineedit matches the name of one added contact.
   465             // If this itemInLineedit matches the name of one added contact.
   279             if (indexInAddedContactsName >= 0) {
   466             if (indexInAddedContactsName >= 0) {
   280                 // Add the recipient into mEmailAddressList.
   467                 // Add the recipient into mEmailAddressList.
   281                 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsName));  
   468                 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsName));
   282             }
   469             }
   283             // If this itemInLineedit matches the emailaddress of one added contact.
   470             // If this itemInLineedit matches the emailaddress of one added contact.
   284             else if (indexInAddedContactsAddress >= 0) { 
   471             else if (indexInAddedContactsAddress >= 0) {
   285                 // Add the recipient into mEmailAddressList.
   472                 // Add the recipient into mEmailAddressList.
   286                 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsAddress));  
   473                 mEmailAddressList.append(mRecipientsAddedFromContacts.at(indexInAddedContactsAddress));
   287             }
   474             }
   288             // This itemInLineedit is not added from Contacts
   475             // This itemInLineedit is not added from Contacts
   289             else { 
   476             else {
   290                 // Form the item into NmAddress format.
   477                 // Form the item into NmAddress format.
   291                 NmAddress recipient;
   478                 NmAddress recipient;
   292                 recipient.setAddress(itemInLineedit);
   479                 recipient.setAddress(itemInLineedit);
   293                 // There is no display name info available, so leave display name empty.
   480                 // There is no display name info available, so leave display name empty.
   294                 recipient.setDisplayName(QString()); 
   481                 recipient.setDisplayName(QString());
   295                 // Add this NmAddress formated lineedit item into mEmailAddressList.
   482                 // Add this NmAddress formated lineedit item into mEmailAddressList.
   296                 mEmailAddressList.append(recipient);  
   483                 mEmailAddressList.append(recipient);
   297             }
   484             }
   298         }
   485         }
   299         else { // There is no recipient is added from Contacts
   486         else { // There is no recipient is added from Contacts
   300             // Form the item into NmAddress format.
   487             // Form the item into NmAddress format.
   301             NmAddress recipient;
   488             NmAddress recipient;
   302             recipient.setAddress(itemInLineedit);
   489             recipient.setAddress(itemInLineedit);
   303             // There is no display name info available, so leave display name emapty.
   490             // There is no display name info available, so leave display name emapty.
   304             recipient.setDisplayName(QString()); 
   491             recipient.setDisplayName(QString());
   305             // Add this NmAddress formated lineedit item into mEmailAddressList.
   492             // Add this NmAddress formated lineedit item into mEmailAddressList.
   306             mEmailAddressList.append(recipient);  
   493             mEmailAddressList.append(recipient);
   307         }
   494         }
   308     }
   495     }
   309 }
   496 }
   310 
   497 
   311 
   498 
   313    This Slot is called when the lineedit text changes.
   500    This Slot is called when the lineedit text changes.
   314 */
   501 */
   315 void NmRecipientLineEdit::handleTextChanged(const QString &text)
   502 void NmRecipientLineEdit::handleTextChanged(const QString &text)
   316 {
   503 {
   317     NM_FUNCTION;
   504     NM_FUNCTION;
   318     
   505 
   319     Q_UNUSED(text);
       
   320     mNeedToGenerateEmailAddressList = true;
   506     mNeedToGenerateEmailAddressList = true;
   321 }
   507 
   322 
   508     //if there is no text, hide popup already
   323 /*
   509     if (document()->isEmpty()) {
   324  * If recipient is added from Contacts by Contacts, we need to add it to the list.
   510         hideAutofillPopup();
       
   511     }
       
   512 
       
   513     if (mContactHistoryModel) {
       
   514         int startPos(-1), length(-1);
       
   515         currentTextPart(startPos, length);
       
   516         QString t = text.mid(startPos, length);
       
   517         if (t.length()) {
       
   518             mContactHistoryModel->query(t);
       
   519         }
       
   520     }
       
   521 }
       
   522 
       
   523 /*!
       
   524     If recipient is added from Contacts by Contacts, we need to add it to the list.
   325  */
   525  */
   326 void NmRecipientLineEdit::addContacts(QList<NmAddress *> contacts)
   526 void NmRecipientLineEdit::addContacts(QList<NmAddress *> contacts)
   327 {
   527 {
   328     foreach (NmAddress *nmContact,contacts) {
   528     foreach (NmAddress *nmContact,contacts) {
   329         if (nmContact && nmContact->displayName().length() > 0) {
   529         if (nmContact && nmContact->displayName().length() > 0) {
   330             mRecipientsAddedFromContacts.append(*nmContact);
   530             mRecipientsAddedFromContacts.append(*nmContact);
   331             mNeedToGenerateEmailAddressList = true;
   531             mNeedToGenerateEmailAddressList = true;
   332         }
   532         }
   333     }
   533     }
   334 }
   534 }
       
   535 
       
   536 /*!
       
   537    This Slot appends the selected contact to the end of the lineedit content.
       
   538 */
       
   539 void NmRecipientLineEdit::addSelectedContactFromHistory(const QModelIndex &modelIndex)
       
   540 {
       
   541     NM_FUNCTION;
       
   542 
       
   543     // ignore text changes during handling of text
       
   544     disconnect(this, SIGNAL(textChanged(QString)),
       
   545                this, SLOT(handleTextChanged(QString)));
       
   546 
       
   547     // Get address from contact history model
       
   548     NmAddress contact;
       
   549     getChosenAddressFromModel(modelIndex, contact);
       
   550 
       
   551     if (!contact.address().isEmpty()) {
       
   552         // Add the recipient to internal list of addresses
       
   553         mRecipientsAddedFromContacts.append(contact);
       
   554 
       
   555         // Find the text part to be replaced
       
   556         int startPos(-1), length(-1);
       
   557         currentTextPart(startPos, length);
       
   558 
       
   559         // delete currently entered characters before adding replacement
       
   560         QTextCursor cursor(textCursor());
       
   561         cursor.setPosition(startPos);
       
   562         for(int i=0; i<length; i++) {
       
   563             cursor.deleteChar();
       
   564         }
       
   565 
       
   566         // Insert replacement text
       
   567         if (contact.displayName().isEmpty()) {
       
   568             insertContactText(contact.address());
       
   569         }
       
   570         else {
       
   571             insertContactText(contact.displayName());
       
   572         }
       
   573     }
       
   574     // Continue accepting text changes..
       
   575     connect(this, SIGNAL(textChanged(QString)),
       
   576             this, SLOT(handleTextChanged(QString)));
       
   577 
       
   578     //hide popup
       
   579     hideAutofillPopup();
       
   580 }
       
   581 /*!
       
   582  reads the chosen data from contact history model
       
   583  */
       
   584 void NmRecipientLineEdit::getChosenAddressFromModel(const QModelIndex &modelIndex, NmAddress &address)
       
   585 {
       
   586     NM_FUNCTION;
       
   587     // Dig out the chosen contact data
       
   588     // Get the activated item with given modelIndex
       
   589     NmContactHistoryModelItem item = mContactHistoryModel->data(modelIndex, Qt::DisplayRole).value<NmContactHistoryModelItem>();
       
   590     if (item.subItemCount()) {
       
   591         QList<NmContactHistoryModelSubItem> itemlist = item.subEntries();
       
   592         if (itemlist.count() == 2) {
       
   593             address.setDisplayName(itemlist[0].mItemText);
       
   594             address.setAddress(itemlist[1].mItemText);
       
   595         } else if (itemlist.count() == 1) {
       
   596             // only emailaddress found (no display name)
       
   597             address.setAddress(itemlist[0].mItemText);
       
   598         }
       
   599     }
       
   600 }
       
   601 
       
   602 /*!
       
   603  finds the current "entry" (startindex+length) based on current cursor position.
       
   604  Excludes possible trailing delimiter
       
   605  */
       
   606 void NmRecipientLineEdit::currentTextPart(int &startIndex, int &length)
       
   607 {
       
   608     NM_FUNCTION;
       
   609 
       
   610     // Get current cursor position in the text
       
   611     int currentPos = textCursor().position();
       
   612 
       
   613     QString tmp_debug = text();
       
   614     startIndex = qMax(text().lastIndexOf(NmRecipientLineEditSemicolon,currentPos-1), 0);
       
   615     if (startIndex>0) {
       
   616         startIndex+=2; // in case entry is not the first, advance the start index by amount of "; ".
       
   617     }
       
   618 
       
   619 
       
   620     int nextDelimiterIndex=text().indexOf(NmRecipientLineEditDelimiter,currentPos);
       
   621     if (nextDelimiterIndex==-1) {
       
   622         // no delim after current pos
       
   623         length=text().length()-startIndex;
       
   624     }
       
   625     else {
       
   626         // delim after current pos found
       
   627         length=nextDelimiterIndex-startIndex;
       
   628     }
       
   629 }
       
   630 
       
   631 /*!
       
   632     Helper function for creating autofill component.
       
   633 */
       
   634 void NmRecipientLineEdit::createAutofillComponents()
       
   635 {
       
   636     NM_FUNCTION;
       
   637     
       
   638     //create model
       
   639     mContactHistoryModel = new NmContactHistoryModel(EmailAddressModel);
       
   640     connect(mContactHistoryModel,SIGNAL(modelCompleted(int)),this,SLOT(modelCompleted(int)));
       
   641 
       
   642     //create popup list components
       
   643     HbDocumentLoader loader;
       
   644     bool loadingOk(false);
       
   645     loader.load(FILE_PATH_AUTOFILL_DOCML, &loadingOk);
       
   646     if (loadingOk){
       
   647         mAutofillListView = dynamic_cast<HbListView*>(loader.findWidget("listview"));
       
   648     }
       
   649     else {
       
   650         NM_COMMENT("mAutofillListView loading from docML failed.");
       
   651         return; 
       
   652     }
       
   653     
       
   654     connect(mAutofillListView, SIGNAL(activated(const QModelIndex &)),
       
   655             this, SLOT(addSelectedContactFromHistory(const QModelIndex &)));
       
   656 
       
   657     mAutofillListViewItem = new NmAutoFillListViewItem();
       
   658     mAutofillListView->setModel(static_cast<QAbstractListModel*>(mContactHistoryModel),mAutofillListViewItem);
       
   659 
       
   660     //create popup
       
   661     createAutoFillPopup();
       
   662 
       
   663     //set layout for popup
       
   664     QGraphicsLinearLayout *linLayout = new QGraphicsLinearLayout(Qt::Horizontal,
       
   665                                                                  mAutoFillPopup);
       
   666     linLayout->addItem(mAutofillListView);
       
   667 
       
   668 }
       
   669 
       
   670 /*!
       
   671   Helper function for creating popup component.
       
   672 */
       
   673 void NmRecipientLineEdit::createAutoFillPopup()
       
   674 {
       
   675     NM_FUNCTION;
       
   676     mAutoFillPopup = new HbPopup(this);
       
   677     mAutoFillPopup->setVisible(false);
       
   678     mAutoFillPopup->setFlag(QGraphicsItem::ItemIsPanel, true);
       
   679     mAutoFillPopup->setActive(false);
       
   680     mAutoFillPopup->setFocusPolicy(Qt::NoFocus);
       
   681     mAutoFillPopup->setBackgroundFaded(false);
       
   682     mAutoFillPopup->setDismissPolicy(HbPopup::TapOutside);
       
   683     mAutoFillPopup->setTimeout(HbPopup::NoTimeout);
       
   684     mAutoFillPopup->setFrameType(HbPopup::Weak); //uses qtg_fr_popup_secondary graphics
       
   685     HbStyle::setItemName(mAutoFillPopup, QString("autoFillPopup"));
       
   686 
       
   687     mPopupBackground = new NmPopupBackground(mAutoFillPopup, this);
       
   688     mPopupBackground->setVisible(false);
       
   689     mPopupBackground->setZValue(mAutoFillPopup->zValue() - 1);
       
   690 }
       
   691 
       
   692 /*!
       
   693   Helper function for showing autofill popup.
       
   694 */
       
   695 void NmRecipientLineEdit::showAutofillPopup()
       
   696 {
       
   697     NM_FUNCTION;
       
   698     if (!mAutoFillPopup->isVisible()) {
       
   699         parentItem()->setZValue(NmRecipientLineEditForegroundZValue);
       
   700         mAutoFillPopup->show();
       
   701         mPopupBackground->setVisible(true);
       
   702     }
       
   703 }
       
   704 
       
   705 /*!
       
   706   Helper function for hiding autofill popup.
       
   707 */
       
   708 void NmRecipientLineEdit::hideAutofillPopup()
       
   709 {
       
   710     NM_FUNCTION;
       
   711     if (mAutoFillPopup->isVisible()) {
       
   712         mPopupBackground->setVisible(false);
       
   713         parentItem()->setZValue(NmRecipientLineEditBackgroundZValue);
       
   714         mAutoFillPopup->hide();
       
   715     }
       
   716 }
       
   717 
       
   718 /*!
       
   719   Slot for listening when model is ready with a new data.
       
   720 */
       
   721 void NmRecipientLineEdit::modelCompleted(int err)
       
   722 {
       
   723     NM_FUNCTION;
       
   724     if (err == 0) {
       
   725         //show model if there was findings
       
   726         int count = mContactHistoryModel->rowCount(QModelIndex());
       
   727 
       
   728         if (count > 0) {
       
   729             showAutofillPopup();
       
   730         } else {
       
   731             hideAutofillPopup();
       
   732         }
       
   733     }
       
   734 }
       
   735 
       
   736 /*!
       
   737  finds the current "entry" in the editor field based on current cursor position and creates a selection of it.
       
   738  Includes possible trailing delimiter
       
   739  */
       
   740 void NmRecipientLineEdit::setHighlight(int currentPos)
       
   741 {
       
   742     QString txt = text();
       
   743 
       
   744     int startPos = qMax(txt.lastIndexOf(NmRecipientLineEditDelimiter,currentPos), 0);
       
   745     if (startPos) {
       
   746         startPos+=2; // in case entry is not the first, advance the start index by amount of "; "
       
   747     }
       
   748     int endPos = qMax(txt.indexOf(NmRecipientLineEditDelimiter,currentPos), currentPos);
       
   749 
       
   750     if (startPos >= 0 && endPos >= 0 && startPos != endPos) {
       
   751         setSelection(startPos, endPos - startPos + 2);
       
   752     }
       
   753     else {
       
   754         deselect();
       
   755     }
       
   756 
       
   757     update();
       
   758 }
       
   759 
       
   760 /*!
       
   761  inserts a new contact text (underlined) + trailing delimiter to current cursor position in editor field
       
   762  */
       
   763 void NmRecipientLineEdit::insertContactText(const QString &text)
       
   764     {
       
   765     NM_FUNCTION;
       
   766 
       
   767     // Insert contact text as underlined
       
   768     QTextCharFormat colorFormat(textCursor().charFormat());
       
   769     QColor fgColor = colorFormat.foreground().color();
       
   770     fgColor.setAlpha(NmRecipientLineEditFadedAlpha);
       
   771     colorFormat.setUnderlineColor(fgColor);
       
   772     colorFormat.setFontUnderline(true);
       
   773     textCursor().insertText(text, colorFormat);
       
   774 
       
   775     // Insert delimiter (not underlined)
       
   776     colorFormat.setFontUnderline(false);
       
   777     textCursor().insertText(NmRecipientLineEditDelimiter,colorFormat);
       
   778     }
       
   779 
       
   780 /*!
       
   781     Popup's background item. Used to close properly popup if clicked to outside of the popup.
       
   782  */
       
   783 NmPopupBackground::NmPopupBackground(HbPopup * popup, QGraphicsItem *parent) :
       
   784     QGraphicsItem(parent),
       
   785     mPopup(popup)
       
   786 {
       
   787     // This is needed to be able to block moving the focus to items behind background item by
       
   788     // clicking on them.
       
   789     setFlag(QGraphicsItem::ItemIsFocusable);
       
   790     setFlag(QGraphicsItem::ItemIsPanel);
       
   791 }
       
   792 
       
   793 /*!
       
   794     Paint. Not used but since this is pure virtual it must be here. 
       
   795  */
       
   796 void NmPopupBackground::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
       
   797 {
       
   798     Q_UNUSED(option)
       
   799     Q_UNUSED(widget);
       
   800     Q_UNUSED(painter);
       
   801 }
       
   802 
       
   803 /*!
       
   804     Mouse press events are checked here. If background is clicked, popup must be closed. 
       
   805  */
       
   806 bool NmPopupBackground::sceneEvent(QEvent *event)
       
   807 {
       
   808     if (event->type() == QEvent::GraphicsSceneMousePress) {
       
   809         mPopup->close();
       
   810         setVisible(false);
       
   811         event->accept();
       
   812         return true;
       
   813     }
       
   814     else {
       
   815         event->ignore();
       
   816         return QGraphicsItem::sceneEvent(event);
       
   817     }
       
   818 }