messagingapp/msgui/unifiededitor/src/msgunifiededitorlineedit.cpp
changeset 34 84197e66a4bd
parent 31 ebfee66fde93
child 36 844a5921f85b
child 43 35b64624a9e7
equal deleted inserted replaced
31:ebfee66fde93 34:84197e66a4bd
     1 /*
       
     2  * Copyright (c) 2009 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:
       
    15  *
       
    16  */
       
    17 
       
    18 #include <QGraphicsSceneMouseEvent>
       
    19 #include "msgunifiededitorlineedit.h"
       
    20 
       
    21 const QRegExp expr("[,;\n]$");
       
    22 const QRegExp sepAtEnd("; $");
       
    23 const QRegExp sepAtMiddle("; ");
       
    24 
       
    25 const QString replacementStr("; ");
       
    26 const QString labelSeperator(": ");
       
    27 
       
    28 const int fadedAlpha(125);
       
    29 const int solidAlpha(255);
       
    30 
       
    31 const int SNAP_DELAY = 350;
       
    32 
       
    33 MsgUnifiedEditorLineEdit::MsgUnifiedEditorLineEdit(const QString& label,QGraphicsItem *parent):
       
    34 HbLineEdit(parent),
       
    35 mSelectionStart(-1),
       
    36 mSelectionEnd(-1),
       
    37 mDefaultBehaviour(false)
       
    38 {
       
    39     QString labelStr = label.trimmed();
       
    40     
       
    41     QTextCursor cursor(this->textCursor());
       
    42     QTextCharFormat colorFormat(cursor.charFormat());
       
    43    
       
    44     QColor fgColor = this->palette().color(QPalette::Text);     
       
    45     fgColor.setAlpha(fadedAlpha);
       
    46     colorFormat.setForeground(fgColor);
       
    47     cursor.insertText(labelStr , colorFormat);
       
    48 
       
    49     fgColor.setAlpha(solidAlpha);
       
    50     colorFormat.setForeground(fgColor);
       
    51 
       
    52     cursor.insertText(" ",colorFormat);    
       
    53 
       
    54     mLabelExpr.setPattern(QString("^"+labelStr+" $"));
       
    55     mLabel = labelStr+" ";
       
    56 
       
    57     connect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
    58             this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
    59     connect(this, SIGNAL(contentsChanged()), this, SLOT(onContentsChanged()));
       
    60 }
       
    61 
       
    62 MsgUnifiedEditorLineEdit::~MsgUnifiedEditorLineEdit()
       
    63 {
       
    64 }
       
    65 
       
    66 void MsgUnifiedEditorLineEdit::inputMethodEvent(QInputMethodEvent *event)
       
    67 {
       
    68     //let it go in default way.
       
    69     if(mDefaultBehaviour)
       
    70     {
       
    71         HbAbstractEdit::inputMethodEvent(event);
       
    72         event->accept();
       
    73         return;
       
    74     }
       
    75 
       
    76     if (!event->commitString().isEmpty() || event->replacementLength())
       
    77     {
       
    78         if (event->commitString().contains(expr))
       
    79         {
       
    80             if(this->text().isEmpty() || this->text().contains(sepAtEnd) || this->text().contains(mLabelExpr))
       
    81             {
       
    82                 event->accept();
       
    83                 return;
       
    84             }
       
    85 
       
    86             this->setCursorPosition(this->text().length());
       
    87 
       
    88             QString str = event->commitString();
       
    89             str.replace(expr, replacementStr);            
       
    90 
       
    91             event->setCommitString(str, event->replacementStart(), event->replacementLength());            
       
    92         }
       
    93         else if(this->hasSelectedText())
       
    94         {// all user inputs get appended at the end
       
    95             this->setCursorPosition(this->text().length());
       
    96         }
       
    97 
       
    98         HbAbstractEdit::inputMethodEvent(event);
       
    99         event->accept();
       
   100     }
       
   101 }
       
   102 
       
   103 void MsgUnifiedEditorLineEdit::keyPressEvent(QKeyEvent *event)
       
   104 {
       
   105     QString str = event->text();
       
   106 
       
   107     if(event->key()== Qt::Key_Enter || event->key()== Qt::Key_Return)
       
   108     {
       
   109         if(mDefaultBehaviour)
       
   110         {
       
   111             HbAbstractEdit::keyReleaseEvent(event);
       
   112             event->accept();
       
   113             return;
       
   114         }
       
   115         if(this->text().isEmpty() || this->text().contains(sepAtEnd) || this->text().contains(mLabelExpr))
       
   116         {
       
   117             event->accept();
       
   118             return;
       
   119         }
       
   120         this->setCursorPosition(this->text().length());
       
   121         str = replacementStr;
       
   122         QKeyEvent eve(event->type(), Qt::Key_Any, event->modifiers(), str);
       
   123         HbAbstractEdit::keyPressEvent(&eve);
       
   124         event->accept();
       
   125         return;
       
   126     }
       
   127 
       
   128     if(event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete )
       
   129     {
       
   130         int pos = this->cursorPosition();
       
   131         bool pbkContact = true;
       
   132 
       
   133         if(!this->hasSelectedText())
       
   134         {
       
   135             this->setCursorPosition(pos-2);
       
   136             pbkContact = this->textCursor().charFormat().fontUnderline();
       
   137             this->setCursorPosition(pos);
       
   138         }
       
   139 
       
   140         QString text = this->text();
       
   141         text = text.left(pos);
       
   142 
       
   143         if(text.contains(mLabelExpr))
       
   144         {
       
   145             event->accept();
       
   146             return;
       
   147         }
       
   148 
       
   149         if(pbkContact)
       
   150         {
       
   151             //if already selected delete it.
       
   152             if(this->hasSelectedText())
       
   153             {
       
   154                 // deleting phbkContact is an atomic operation
       
   155                 // ensure that the signal is emitted only once
       
   156                 disconnect(this, SIGNAL(contentsChanged()), 
       
   157                         this, SLOT(onContentsChanged()));
       
   158                 HbLineEdit::keyPressEvent(event);
       
   159                 event->accept();
       
   160                 //delete seperator (i.e."; ").
       
   161                 QKeyEvent eve(event->type(), Qt::Key_Delete, Qt::NoModifier);
       
   162                 HbLineEdit::keyPressEvent(&eve);
       
   163                 HbLineEdit::keyPressEvent(&eve);
       
   164                 connect(this, SIGNAL(contentsChanged()), 
       
   165                         this, SLOT(onContentsChanged()));
       
   166                 onContentsChanged();
       
   167             }
       
   168             else //make it selected
       
   169             {                
       
   170                 this->setCursorPosition(pos-3);
       
   171                 setHighlight(pos-3);
       
   172             }
       
   173         }
       
   174         else
       
   175         {
       
   176             QString str = text.right(2);
       
   177             if(str == replacementStr)
       
   178             {
       
   179                 // deleting contact is an atomic operation
       
   180                 // ensure that the signal is emitted only once
       
   181                 disconnect(this, SIGNAL(contentsChanged()), 
       
   182                         this, SLOT(onContentsChanged()));
       
   183                 //delete seperator (i.e."; ").
       
   184                 QKeyEvent eve(event->type(), Qt::Key_Backspace, Qt::NoModifier);
       
   185                 HbLineEdit::keyPressEvent(&eve);
       
   186                 HbLineEdit::keyPressEvent(&eve);
       
   187                 connect(this, SIGNAL(contentsChanged()), 
       
   188                         this, SLOT(onContentsChanged()));
       
   189                 onContentsChanged();
       
   190             }
       
   191             else
       
   192             {
       
   193                 HbLineEdit::keyPressEvent(event);
       
   194             }
       
   195             event->accept();
       
   196         }
       
   197         
       
   198         event->accept();
       
   199         return;
       
   200     }
       
   201 
       
   202     if (event->key() == Qt::Key_Left )
       
   203     {
       
   204         bool selectedText = this->hasSelectedText();
       
   205 
       
   206         //look ahead left.
       
   207         int pos = this->cursorPosition();
       
   208 
       
   209         QString text = this->text();
       
   210         text = text.left(pos);
       
   211 
       
   212         //no text other than label;
       
   213         if(text.contains(mLabelExpr))
       
   214         {
       
   215             event->accept();
       
   216             return;
       
   217         }
       
   218 
       
   219         //look for next seperator while going left.
       
   220         int newPos = text.lastIndexOf(sepAtMiddle);
       
   221 
       
   222         if(newPos < 0 && selectedText)
       
   223         {
       
   224             event->accept();
       
   225             return;
       
   226         }
       
   227 
       
   228         bool pbkContact = true;
       
   229 
       
   230         if(!selectedText)
       
   231         {
       
   232             this->setCursorPosition(pos-2);
       
   233             pbkContact = this->textCursor().charFormat().fontUnderline();
       
   234             this->setCursorPosition(pos);
       
   235         }
       
   236         else
       
   237         {
       
   238             this->setCursorPosition(newPos);
       
   239             pbkContact = this->textCursor().charFormat().fontUnderline();
       
   240             this->setCursorPosition(pos);
       
   241         }
       
   242 
       
   243 
       
   244         if(pbkContact && newPos >0)
       
   245         {
       
   246 
       
   247             setHighlight(newPos-1);
       
   248         }
       
   249         else
       
   250         {
       
   251             //move left, char by char. if seperator met jump over it.
       
   252             if( (newPos > 0 && selectedText) || (pos-2  == newPos))
       
   253             {
       
   254                 this->setCursorPosition(newPos+1);
       
   255             }
       
   256 
       
   257             HbLineEdit::keyPressEvent(event);
       
   258 
       
   259         }
       
   260         event->accept();
       
   261         return;
       
   262     }
       
   263 
       
   264     if (event->key() == Qt::Key_Right)
       
   265     {
       
   266         bool selectedText = this->hasSelectedText();
       
   267 
       
   268         //look ahead.
       
   269         int pos = this->cursorPosition();
       
   270         this->setCursorPosition(pos+3);
       
   271         bool pbkContact = this->textCursor().charFormat().fontUnderline();
       
   272         this->setCursorPosition(pos);
       
   273 
       
   274         //look for next seperator.
       
   275         QString text = this->text();
       
   276         int newPos = text.indexOf(sepAtMiddle,pos+2);
       
   277 
       
   278         if(pbkContact && newPos >0)
       
   279         {
       
   280             this->setCursorPosition(newPos-1);
       
   281             setHighlight(newPos-1);
       
   282         }
       
   283         else
       
   284         {            
       
   285             int seperatorPos = text.indexOf(sepAtMiddle,pos);
       
   286 
       
   287             if(selectedText || seperatorPos == pos)
       
   288             {
       
   289                 this->setCursorPosition(pos+1);
       
   290                 this->deselect();
       
   291             }
       
   292             HbAbstractEdit::keyPressEvent(event);
       
   293         }
       
   294         event->accept();
       
   295         return;
       
   296     }
       
   297 
       
   298     if(!str.isEmpty())
       
   299     {
       
   300         if(mDefaultBehaviour)
       
   301         {
       
   302             HbAbstractEdit::keyPressEvent(event);
       
   303             event->accept();
       
   304             return;
       
   305         }
       
   306         if (str.contains(expr))
       
   307         {
       
   308             if(this->text().isEmpty() || this->text().contains(sepAtEnd) || this->text().contains(mLabelExpr))
       
   309             {
       
   310                 event->accept();
       
   311                 return;
       
   312             }
       
   313 
       
   314             // auto-complete the last incomplete word
       
   315             int contentLength = this->text().length();
       
   316             int pos = this->cursorPosition();
       
   317             QString incompleteWord(this->text().right(contentLength-(pos-1)));
       
   318             if(!incompleteWord.contains(sepAtMiddle))
       
   319             {
       
   320                 this->setCursorPosition(this->text().length());
       
   321             }
       
   322 
       
   323             str.replace(expr, replacementStr);
       
   324             QKeyEvent eve(event->type(), event->key(), event->modifiers(), str);
       
   325             HbAbstractEdit::keyPressEvent(&eve);
       
   326         }
       
   327         else
       
   328         {
       
   329             HbAbstractEdit::keyPressEvent(event);
       
   330             event->accept();
       
   331             return;
       
   332         }
       
   333     }
       
   334 }
       
   335 
       
   336 void MsgUnifiedEditorLineEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
       
   337 {
       
   338     HbAbstractEdit::mouseReleaseEvent(event);
       
   339 
       
   340     int currentPos = this->cursorPosition();
       
   341 
       
   342     QString txt = this->text();
       
   343 
       
   344     QString tempTxt = txt.left(currentPos+2);
       
   345     int seperatorPos = tempTxt.lastIndexOf(sepAtMiddle,currentPos);
       
   346 
       
   347     txt = txt.right(txt.length() - currentPos);
       
   348     int labelPos = txt.indexOf(labelSeperator);
       
   349 
       
   350     if(labelPos >= 0 )//pressed on label.
       
   351     {
       
   352         this->setCursorPosition(currentPos + labelPos + 2);
       
   353     }
       
   354     else if(seperatorPos == currentPos-1 || seperatorPos == currentPos)//pressed just on seperator.
       
   355     {
       
   356         this->setCursorPosition(seperatorPos+2);
       
   357     }
       
   358     else
       
   359     {
       
   360         this->setCursorPosition(currentPos+1);
       
   361         bool pbkContact = this->textCursor().charFormat().fontUnderline();
       
   362         if(pbkContact)
       
   363         {
       
   364             setHighlight(currentPos);
       
   365         }
       
   366     }
       
   367 
       
   368     this->update();
       
   369     event->accept();
       
   370 }
       
   371 
       
   372 void MsgUnifiedEditorLineEdit::setText(const QString& text, bool underlined)
       
   373 {
       
   374 
       
   375     if(!mDefaultBehaviour)
       
   376     {
       
   377         // atomic operation, ensure one signal only at the end
       
   378         disconnect(this, SIGNAL(contentsChanged()), this, SLOT(onContentsChanged()));
       
   379 
       
   380         //make sure previous text is complete.
       
   381         if(this->content().length() > 0)
       
   382         {
       
   383             QInputMethodEvent e;
       
   384             e.setCommitString(";");
       
   385             this->inputMethodEvent(&e);
       
   386         }
       
   387         this->setCursorPosition(this->text().length());
       
   388 
       
   389         QTextCursor cursor(this->textCursor());
       
   390         QTextCharFormat colorFormat(cursor.charFormat());
       
   391         if(underlined)
       
   392         {
       
   393             QColor fgColor = colorFormat.foreground().color();
       
   394             fgColor.setAlpha(fadedAlpha);
       
   395             colorFormat.setUnderlineColor(fgColor);
       
   396             colorFormat.setFontUnderline(true);        
       
   397         }
       
   398         cursor.insertText(text , colorFormat);
       
   399         colorFormat.setFontUnderline(false);
       
   400 
       
   401         cursor.insertText(replacementStr,colorFormat);
       
   402         connect(this, SIGNAL(contentsChanged()), this, SLOT(onContentsChanged()));
       
   403         onContentsChanged();
       
   404     }
       
   405     else
       
   406     {
       
   407        this->setCursorPosition(this->text().length());
       
   408        QTextCursor cursor(this->textCursor());
       
   409        cursor.insertText(text);
       
   410     }
       
   411 }
       
   412 
       
   413 QStringList MsgUnifiedEditorLineEdit::addresses()
       
   414 {
       
   415     QString text = this->content();
       
   416     QStringList list = text.split(replacementStr,QString::SkipEmptyParts);
       
   417     return list;
       
   418 }
       
   419 
       
   420 void MsgUnifiedEditorLineEdit::focusInEvent(QFocusEvent* event)
       
   421 {    
       
   422     HbLineEdit::focusInEvent(event);
       
   423     this->setCursorVisibility(Hb::TextCursorVisible);
       
   424 }
       
   425 
       
   426 void MsgUnifiedEditorLineEdit::focusOutEvent(QFocusEvent* event)
       
   427 {    
       
   428     HbLineEdit::focusOutEvent(event);
       
   429     this->setCursorVisibility(Hb::TextCursorHidden);
       
   430 }
       
   431 
       
   432 void MsgUnifiedEditorLineEdit::setHighlight(int currentPos)
       
   433 {
       
   434     QString txt = this->text();    
       
   435 
       
   436     int endPos = qMax(txt.indexOf(sepAtMiddle,currentPos),
       
   437                       txt.indexOf(labelSeperator,currentPos));
       
   438 
       
   439     int startPos = qMax(txt.lastIndexOf(sepAtMiddle,currentPos),
       
   440                         txt.lastIndexOf(labelSeperator,currentPos));
       
   441 
       
   442     disconnect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   443                this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   444 
       
   445     //highlight if pbk contact.
       
   446     if(startPos > 0 && endPos > 0 && startPos != endPos)
       
   447     {
       
   448         this->setSelection(startPos + 2, endPos - startPos - 2);
       
   449         this->update();
       
   450     }
       
   451     else
       
   452     {
       
   453         this->deselect();
       
   454     }
       
   455 
       
   456     this->update();
       
   457 
       
   458     connect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   459             this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   460 }
       
   461 
       
   462 void MsgUnifiedEditorLineEdit::cut()
       
   463 {
       
   464     HbLineEdit::cut();
       
   465     //after cut delete seperator (i.e."; ").
       
   466     QKeyEvent eve(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier);
       
   467     HbLineEdit::keyPressEvent(&eve);
       
   468     HbLineEdit::keyPressEvent(&eve);
       
   469 }
       
   470 
       
   471 void MsgUnifiedEditorLineEdit::selectAll()
       
   472 {
       
   473     //don't allow user to select every thing.
       
   474     //do nothing.
       
   475 }
       
   476 
       
   477 void MsgUnifiedEditorLineEdit::selectionChanged(const QTextCursor &oldCursor, const QTextCursor& newCursor)
       
   478 {
       
   479 
       
   480     if(mSelectionSnapTimer.isActive())
       
   481     {
       
   482         mSelectionSnapTimer.stop();
       
   483     }
       
   484 
       
   485     if(newCursor.selectionStart() < mLabel.length())
       
   486     {
       
   487         this->setTextCursor(oldCursor);
       
   488         return;
       
   489     }
       
   490 
       
   491     if(!mDefaultBehaviour)
       
   492         {
       
   493         mSelectionStart  = newCursor.selectionStart();
       
   494         mSelectionEnd    = newCursor.selectionEnd();
       
   495 
       
   496         if(mSelectionStart == mSelectionEnd )
       
   497             {
       
   498             return;
       
   499             }
       
   500     
       
   501         mSelectionSnapTimer.start(SNAP_DELAY,this);
       
   502         }
       
   503 }
       
   504 
       
   505 void MsgUnifiedEditorLineEdit::timerEvent(QTimerEvent *event)
       
   506 {
       
   507     //passing event to base class.
       
   508     HbLineEdit::timerEvent(event);
       
   509 
       
   510     if (event->timerId() == mSelectionSnapTimer.timerId())
       
   511     {
       
   512         mSelectionSnapTimer.stop();
       
   513 
       
   514         disconnect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   515                    this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   516 
       
   517         QString txt = this->text();
       
   518 
       
   519         int startPos = qMax(txt.lastIndexOf(sepAtMiddle,mSelectionStart),
       
   520                             txt.lastIndexOf(labelSeperator,mSelectionStart));
       
   521 
       
   522         int endPos = qMax(txt.indexOf(sepAtMiddle,mSelectionEnd),
       
   523                           txt.indexOf(labelSeperator,mSelectionEnd));
       
   524 
       
   525         if(endPos < 0 )
       
   526         {
       
   527             endPos = mSelectionEnd;
       
   528         }
       
   529 
       
   530         this->setSelection(startPos + 2, endPos - startPos - 2);
       
   531 
       
   532         connect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   533                 this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   534 
       
   535         event->accept();
       
   536     }
       
   537 }
       
   538 
       
   539 void MsgUnifiedEditorLineEdit::setDefaultBehaviour(bool defaultBehaviour)
       
   540 {
       
   541     mDefaultBehaviour = defaultBehaviour;
       
   542 }
       
   543 
       
   544 QString MsgUnifiedEditorLineEdit::text() const
       
   545 {
       
   546     return HbLineEdit::text();
       
   547 }
       
   548 
       
   549 QString MsgUnifiedEditorLineEdit::content() const
       
   550 {
       
   551     QString text = this->text();
       
   552     text.remove(mLabel);
       
   553     return text;
       
   554 }
       
   555 
       
   556 void MsgUnifiedEditorLineEdit::clearContent()
       
   557 {
       
   558     // avoid getting updates during local editing
       
   559     disconnect(this, SIGNAL(contentsChanged()), this, SLOT(onContentsChanged()));
       
   560     
       
   561     int startPos = mLabel.length();
       
   562     this->setSelection(startPos, content().length());
       
   563     QKeyEvent eve(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
       
   564     this->keyPressEvent(&eve);
       
   565     this->deselect();
       
   566 
       
   567     // re-connect signal to start getting updates
       
   568     connect(this, SIGNAL(contentsChanged()), this, SLOT(onContentsChanged()));
       
   569 }
       
   570 
       
   571 void MsgUnifiedEditorLineEdit::onContentsChanged()
       
   572 {
       
   573     emit contentsChanged(content());
       
   574 }
       
   575 
       
   576 void MsgUnifiedEditorLineEdit::highlightInvalidString(QString invalidStr)
       
   577 {
       
   578     // for only address editor
       
   579     if(!mDefaultBehaviour)
       
   580     {
       
   581         QString txtContent = this->text();
       
   582         int searchStartPos = mLabel.length();
       
   583         int startPos = txtContent.indexOf(invalidStr, searchStartPos);
       
   584         disconnect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   585                    this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   586         // if invalidStr found
       
   587         if(startPos > 0)
       
   588         {
       
   589             this->setSelection(startPos, invalidStr.length());
       
   590         }
       
   591         connect(this,SIGNAL(selectionChanged(QTextCursor,QTextCursor)),
       
   592                 this,SLOT(selectionChanged(QTextCursor,QTextCursor)));
       
   593     }
       
   594 }
       
   595 
       
   596 // eof