src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbPlugins module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 #include <QTextCharFormat>
       
    26 #include <hbinputpredictionengine.h>
       
    27 #include <hbinputsettingproxy.h>
       
    28 #include <hbinputpredictionfactory.h>
       
    29 #include <hbinputkeymap.h>
       
    30 #include <hbinputkeymapfactory.h>
       
    31 #include <hbinputdialog.h>
       
    32 #include <hbaction.h>
       
    33 #include <hbinputvkbhost.h>
       
    34 #include <hbcolorscheme.h>
       
    35 #include <hbinpututils.h>
       
    36 #include "../touchinput/virtualqwerty.h"
       
    37 
       
    38 #include "hbinputpredictionhandler_p.h"
       
    39 #include "hbinputabstractbase.h"
       
    40 
       
    41 #define HbDeltaHeight 3.0
       
    42 
       
    43 HbInputPredictionHandlerPrivate::HbInputPredictionHandlerPrivate()
       
    44     :mEngine(0),
       
    45     mCandidates(0),
       
    46     mBestGuessLocation(0),
       
    47     mShowTail(true),
       
    48     mTailShowing(false),
       
    49     mAutoAddedSpace(true),
       
    50     mCanContinuePrediction(true),
       
    51     mShowTooltip(true)
       
    52 {
       
    53 }
       
    54 
       
    55 HbInputPredictionHandlerPrivate::~HbInputPredictionHandlerPrivate()
       
    56 {
       
    57     if (mCandidates) {
       
    58         delete mCandidates;
       
    59         mCandidates = 0;
       
    60     }
       
    61 }
       
    62 
       
    63 void HbInputPredictionHandlerPrivate::deleteOneCharacter()
       
    64 {
       
    65     mShowTail = true;
       
    66     mShowTooltip = true;
       
    67     // A backspace in predictive means updating the engine for the delete key press
       
    68     // and get the new candidate list from the engine.
       
    69     if ((mEngine->inputLength() >= 1) || selectWord()) {
       
    70         //Only autocomplition part should be deleted when autocompliton part is enable and user pressed a delete key
       
    71         if(false == mTailShowing) {
       
    72             mEngine->deleteKeyPress( this );
       
    73         }
       
    74         //To prevent showing autocompletion part while deleting the characters using backspace key
       
    75         mShowTail = false;
       
    76         mShowTooltip = false;
       
    77 		if (mEngine->inputLength() > 0) {
       
    78             bool unused = false;
       
    79             mEngine->updateCandidates(mBestGuessLocation, unused);
       
    80             if (!mCandidates->count()) {
       
    81                 mCandidates->append(mEngine->currentWord());
       
    82             }
       
    83 		}
       
    84 		mCanContinuePrediction = true;
       
    85 		// update the editor with the new preedit text.
       
    86         updateEditor();
       
    87         return;
       
    88     }
       
    89 
       
    90     HbInputFocusObject* focusedObject = 0;
       
    91     focusedObject = mInputMethod->focusObject();
       
    92     if (!focusedObject) {
       
    93         return;
       
    94     }
       
    95 
       
    96     if ((focusedObject->inputMethodQuery(Qt::ImCursorPosition).toInt() >= 0) || focusedObject->preEditString().length()) {
       
    97         QList<QInputMethodEvent::Attribute> list;
       
    98         QInputMethodEvent event(QString(), list);
       
    99         event.setCommitString(QString(), -1, 1);
       
   100         commit(event);
       
   101     }
       
   102 }
       
   103 
       
   104 void HbInputPredictionHandlerPrivate::commitAndAppendCharacter(QChar character)
       
   105 {
       
   106     if (!mEngine) {
       
   107         return;
       
   108     }
       
   109 
       
   110     HbInputFocusObject* focusedObject = 0;
       
   111     focusedObject = mInputMethod->focusObject();
       
   112     if (!focusedObject) {
       
   113         return;
       
   114     }
       
   115 
       
   116     QString commitString;
       
   117     if (mEngine->inputLength() > 0 && mCandidates->count() > 0) {
       
   118         if(mCandidates->count() <= mBestGuessLocation) {
       
   119             commitString = mCandidates->at(0);
       
   120             mEngine->addUsedWord(mCandidates->at(0));
       
   121         } else if (mShowTail == false) {
       
   122             commitString = mCandidates->at(mBestGuessLocation).left(mEngine->inputLength());
       
   123             mEngine->addUsedWord(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()));
       
   124         } else {
       
   125             commitString = mCandidates->at(mBestGuessLocation);
       
   126             mEngine->addUsedWord(mCandidates->at(mBestGuessLocation));
       
   127         }
       
   128         if (character == QChar(' ') || character == QChar('\n')) {
       
   129             mAutoAddedSpace = true;
       
   130         }
       
   131         commit(commitString);
       
   132     } else {
       
   133         mAutoAddedSpace = false;
       
   134     }
       
   135     commitString = character;
       
   136     commit(commitString);
       
   137 }
       
   138 
       
   139 /*!
       
   140 Commits the candidate upon closing of the candidate list. Now can the closing key be anything other than
       
   141 just selection. Need to evaluate this. When the candidate list is visible, the current implementation of the
       
   142 candidate list does not allow the virtual keypad to be clicked.
       
   143 */
       
   144 void HbInputPredictionHandlerPrivate::candidatePopupClosed(int closingKey, const QString& activatedText)
       
   145 {
       
   146     if (!mEngine) {
       
   147         return;
       
   148     }
       
   149 
       
   150     HbInputFocusObject* focusedObject = 0;
       
   151     focusedObject = mInputMethod->focusObject();
       
   152     if (!focusedObject) {
       
   153         return;
       
   154     }
       
   155 
       
   156     QString commitString  = activatedText;
       
   157     if (closingKey == Qt::Key_0 || closingKey == Qt::Key_Space) {
       
   158         commitString = activatedText+' ';
       
   159     } else if (closingKey == Qt::Key_Enter || closingKey == Qt::Key_Return) {
       
   160         commitString = activatedText;
       
   161         commit(commitString);
       
   162         commitString = '\n';
       
   163     }
       
   164 
       
   165     commit(commitString,true);
       
   166 }
       
   167 
       
   168 /*!
       
   169 This function shows the exact popup if needed.
       
   170 */
       
   171 void HbInputPredictionHandlerPrivate::showExactWordPopupIfNeeded()
       
   172 {
       
   173     Q_Q(HbInputPredictionHandler);
       
   174     if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \
       
   175         != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) {                
       
   176         q->processExactWord(mCandidates->at(0));
       
   177     } else {
       
   178         QString empty;
       
   179         q->processExactWord(empty);
       
   180     }
       
   181 }
       
   182 
       
   183 QList<HbKeyPressProbability> HbInputPredictionHandlerPrivate::probableKeypresses()
       
   184 {
       
   185     if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
       
   186         //Useof the concrete input method implementations make the modehandlersin flexible.
       
   187         //Later an intermediate abstract class needsto be introduced.
       
   188         HbVirtualQwerty * qwertyInputMethod = qobject_cast<HbVirtualQwerty*>(mInputMethod);
       
   189         if(qwertyInputMethod) {
       
   190             return qwertyInputMethod->probableKeypresses();
       
   191         }
       
   192     }
       
   193     return QList<HbKeyPressProbability>();
       
   194 }
       
   195 
       
   196 /*!
       
   197 This sets the selected candidate from the candidate list as the editor text.
       
   198 */
       
   199 bool HbInputPredictionHandlerPrivate::selectWord(bool selectFromLeft)
       
   200 {
       
   201     if (!mEngine) {
       
   202         return false;
       
   203     }
       
   204     mShowTail = false;
       
   205 
       
   206     HbInputFocusObject* focusedObject = 0;
       
   207     focusedObject = mInputMethod->focusObject();
       
   208     if(!focusedObject) {
       
   209         return false;
       
   210     }
       
   211     // No word selected, if we move next to a word on left side, select it
       
   212     int cursorPos = focusedObject->inputMethodQuery(Qt::ImCursorPosition).toInt();
       
   213 
       
   214     QString text = focusedObject->inputMethodQuery(Qt::ImSurroundingText).toString();
       
   215     if ((cursorPos > 0 && selectFromLeft) || (cursorPos < text.length() && !selectFromLeft)) {
       
   216         int start;
       
   217         int end;
       
   218         if (selectFromLeft && cursorPos>=1 &&!text.at(cursorPos-1).isSpace()) {
       
   219             // selecting word from left side of cursor
       
   220             end = cursorPos;
       
   221             for(start = end; start > 0; start--) {
       
   222                 if (text.at(start-1).isSpace()) {
       
   223                     break;
       
   224                 }
       
   225             }
       
   226         } else if (!selectFromLeft && !text.at(cursorPos).isSpace()) {
       
   227             // selecting word from right side of cursor
       
   228             start = cursorPos;
       
   229             for(end = start; end < text.length(); ++end) {
       
   230                 if (text.at(end).isSpace()) {
       
   231                     break;
       
   232                 }
       
   233             }
       
   234         } else {
       
   235             // no word in the direction where cursor is moving
       
   236             return false;
       
   237         }
       
   238         int length = end-start;
       
   239         // update internal state and editor
       
   240         if(length > 0){
       
   241             mEngine->setWord(text.mid(start, length), this);
       
   242         }
       
   243         bool unused = false;
       
   244         mEngine->updateCandidates(mBestGuessLocation, unused);
       
   245         //With selection we can always continue predicting, even when the selection 
       
   246         //is not a well predicted word.
       
   247         if (!mCandidates->count()) {
       
   248             //Here we are making sure that even if the engine does not return any candidate
       
   249             //for given input sequence, the candidate list is non-empty. In such a scenario
       
   250             //the candidate list will contain the actual selection or the exact word.
       
   251             mCandidates->append(mEngine->currentWord());
       
   252         }
       
   253         //
       
   254         QTextCharFormat underlined;
       
   255         QList<QInputMethodEvent::Attribute> list;
       
   256         underlined.setFontUnderline(true);
       
   257         QInputMethodEvent::Attribute textstyle(QInputMethodEvent::TextFormat, 0, mEngine->inputLength(), underlined);
       
   258         list.append(textstyle);
       
   259         QInputMethodEvent event(mCandidates->at(0), list);
       
   260         event.setCommitString(QString(), (selectFromLeft ? -length : 0), length);
       
   261         focusedObject->sendEvent(event);
       
   262         return true;
       
   263     } else {
       
   264         return false;
       
   265     }
       
   266 }
       
   267 
       
   268 /*!
       
   269 This method updates the editor contents based on the candidates available in the candidate list.
       
   270 */
       
   271 void HbInputPredictionHandlerPrivate::updateEditor()
       
   272 {
       
   273     Q_Q(HbInputPredictionHandler);
       
   274     if (!mEngine) {
       
   275         return;
       
   276     }
       
   277 
       
   278     QList<QInputMethodEvent::Attribute> list;
       
   279     QTextCharFormat underlined;
       
   280     HbInputFocusObject *focusedObject = 0;
       
   281     underlined.setFontUnderline(true);
       
   282     QInputMethodEvent::Attribute textstyle(QInputMethodEvent::TextFormat, 0, mEngine->inputLength(), underlined);
       
   283     list.append(textstyle);
       
   284 
       
   285     focusedObject = mInputMethod->focusObject();
       
   286     Q_ASSERT(focusedObject);
       
   287 
       
   288     if (mEngine->inputLength() == 0) {
       
   289         QInputMethodEvent event(QString(), list);
       
   290         q->sendAndUpdate(event);
       
   291     } else {
       
   292         if (mCandidates->count() > mBestGuessLocation) {
       
   293             int taillength = mCandidates->at(mBestGuessLocation).length() - mEngine->inputLength();
       
   294             if (taillength > 0 && mShowTail) {
       
   295                 // TODO: Color from skin should be used
       
   296 				QColor col = HbColorScheme::color("qtc_editor_hint_normal");
       
   297                 QBrush brush(col);
       
   298                 QTextCharFormat gray;
       
   299                 gray.setForeground(brush);
       
   300                 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, mEngine->inputLength(), taillength, gray));
       
   301 				list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mEngine->inputLength(), 0, 0));
       
   302                 QInputMethodEvent event(mCandidates->at(mBestGuessLocation), list);
       
   303                 focusedObject->sendEvent(event);
       
   304                 mTailShowing = true;
       
   305             } else {
       
   306 				list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mCandidates->at(mBestGuessLocation).length(), 0, 0));
       
   307                 QInputMethodEvent event(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()), list);
       
   308                 focusedObject->sendEvent(event);
       
   309                 mTailShowing = false;
       
   310             }
       
   311             if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \
       
   312                 != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) {                
       
   313                     q->processExactWord(mCandidates->at(0));
       
   314             } else {
       
   315                 QString empty;
       
   316                 q->processExactWord(empty);
       
   317             }
       
   318         } else {
       
   319             QInputMethodEvent event(QString(""), list);
       
   320             focusedObject->sendEvent(event);
       
   321         }
       
   322     }
       
   323 }
       
   324 
       
   325 bool HbInputPredictionHandlerPrivate::filterEvent(const QKeyEvent * event)
       
   326 {
       
   327     HbInputFocusObject* focusObject = 0;
       
   328     focusObject = mInputMethod->focusObject();
       
   329     //If the focused object is NULL or the key event is improper, can not continue
       
   330     if(!focusObject || (event->key()<0)) {
       
   331         return false;
       
   332     }
       
   333 
       
   334     Q_Q(HbInputPredictionHandler);
       
   335     if (!mEngine) {
       
   336         return false;
       
   337     }
       
   338 
       
   339     bool ret = false;
       
   340     mModifiers = Qt::NoModifier;   
       
   341     mCanContinuePrediction = true;
       
   342     switch (event->key()) {
       
   343     case Qt::Key_Backspace:
       
   344     case Qt::Key_Delete:
       
   345         {
       
   346             QString currentSelection = focusObject->inputMethodQuery(Qt::ImCurrentSelection).toString();
       
   347             if(currentSelection.length()) {
       
   348                 QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);		
       
   349                 q->sendAndUpdate(event);
       
   350                 event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier);
       
   351                 q->sendAndUpdate(event);
       
   352             } else {
       
   353                 deleteOneCharacter();
       
   354             }
       
   355 		}
       
   356         ret = true;
       
   357         break;
       
   358     case Qt::Key_Period: // TODO: better handling for punctuation
       
   359     case Qt::Key_Comma: { // Need to take fn, shift etc. in account
       
   360             HbModifier modifier = HbModifierNone;
       
   361             int currentTextCase = focusObject->editorInterface().textCase();
       
   362             if ( HbTextCaseUpper == currentTextCase || HbTextCaseAutomatic == currentTextCase ) {
       
   363                 modifier = HbModifierShiftPressed;
       
   364             }
       
   365             QString qc;
       
   366             const HbMappedKey* mappedKey = mKeymap->keyForKeycode(mInputMethod->inputState().keyboard(), event->key());
       
   367 
       
   368             if (mappedKey) {
       
   369                 if (modifier == HbModifierNone) {
       
   370                     qc = mappedKey->characters(HbModifierNone).left(1);
       
   371                 } else if (modifier == HbModifierShiftPressed) {
       
   372                     qc = mappedKey->characters(HbModifierShiftPressed).left(1);
       
   373                 }
       
   374             }
       
   375 
       
   376             if (mEngine->inputLength() == 0) {
       
   377                 QList<QInputMethodEvent::Attribute> list;
       
   378                 QInputMethodEvent event(QString(), list);
       
   379                 if (mAutoAddedSpace) {
       
   380                     int cursorPos = mInputMethod->focusObject()->inputMethodQuery(Qt::ImCursorPosition).toInt();
       
   381                     QString text = mInputMethod->focusObject()->inputMethodQuery(Qt::ImSurroundingText).toString();
       
   382                     if (cursorPos > 0 && text.at(cursorPos-1).isSpace()) {
       
   383                         event.setCommitString(qc, -1, 1);
       
   384                     } else {
       
   385                         event.setCommitString(qc);
       
   386                     }
       
   387                 } else {
       
   388                     event.setCommitString(qc);
       
   389                 }
       
   390                 mAutoAddedSpace = false;
       
   391                 q->sendAndUpdate(event);
       
   392             } else {
       
   393                 // Fix for input stopping after ,. keys in qwerty predictive
       
   394                 commitAndAppendCharacter(qc.at(0));
       
   395                 QString empty;
       
   396                 q->processExactWord(empty);
       
   397             }
       
   398             ret = true;
       
   399         }
       
   400         break;
       
   401     case Qt::Key_Return:
       
   402     case Qt::Key_Enter:
       
   403     case Qt::Key_Space:
       
   404     case Qt::Key_0: {//Space
       
   405             // A space means we have to commit the candidates when we are in predictive mode.
       
   406             QChar qc(event->key());
       
   407             if (qc == Qt::Key_Enter) {
       
   408                 qc = QChar('\n');  // Editor expects normal line feed.
       
   409             } else if (qc == Qt::Key_0) {
       
   410                 qc = QChar(' ');
       
   411             }
       
   412             commitAndAppendCharacter(qc);
       
   413             // if exact word popup functionality is on then we should inform exact word popup
       
   414             // about the space.//++TODO
       
   415             QString empty;
       
   416             q->processExactWord(empty);
       
   417             ret = true;
       
   418         }
       
   419         break;
       
   420     default: {
       
   421             mShowTail = true;
       
   422             mShowTooltip = true;
       
   423             mAutoAddedSpace = false;
       
   424             if (q->HbInputModeHandler::filterEvent(event)) {
       
   425                 return true;
       
   426             }
       
   427             if (mEngine) {
       
   428                 int currentTextCase = focusObject->editorInterface().textCase();
       
   429                 if ( HbTextCaseUpper == currentTextCase || HbTextCaseAutomatic == currentTextCase ) {
       
   430                     mModifiers |= Qt::ShiftModifier;
       
   431                 }
       
   432                 mEngine->appendKeyPress(event->key(), mModifiers, mInputMethod->inputState().textCase(), this);
       
   433                 bool isCustomWord = false;
       
   434                 mEngine->updateCandidates(mBestGuessLocation, isCustomWord);
       
   435                 //The engine can not predict the word, it is a custom word. Now engine returns a
       
   436                 //single candidate entry which is actually the previous properly predicted character.
       
   437                 //TODO: In such a scenario, the prediction should stop and there needs to be some way for
       
   438                 //the user to tell the correct word which he wants (Some query editor). But, such a thing is
       
   439                 //not in place and hence the current implementation just appends a "?" and displays the
       
   440                 //previous word itself.
       
   441                 if (isCustomWord && mCandidates->count()) {
       
   442                     QString replacementText = mCandidates->at(0);//+"?";
       
   443                     mCandidates->clear();
       
   444                     mCandidates->append(replacementText);
       
   445                     //Since there is only one candidate, that's the best prediction.
       
   446                     mBestGuessLocation = 0;
       
   447                 }
       
   448                 //We need to check and carry out necessary steps if the engine fails to predict any candidate,
       
   449                 //for the give input sequence.
       
   450                 handleEmptyCandidateList();
       
   451                 updateEditor();
       
   452                 mInputMethod->updateState();
       
   453                 ret = true;
       
   454             }
       
   455         }
       
   456     }
       
   457 
       
   458     return ret;
       
   459 }
       
   460 
       
   461 void HbInputPredictionHandlerPrivate::keyHandlerUnicode(const QChar& character)
       
   462 {
       
   463     if (!mEngine) {
       
   464         return;
       
   465     }
       
   466     mEngine->appendCharacter(character, mInputMethod->inputState().textCase(), this);
       
   467     bool unused = false;
       
   468     mEngine->updateCandidates(mBestGuessLocation, unused);
       
   469     //Check if the candidate list is empty and take necessary steps if so.
       
   470     handleEmptyCandidateList();
       
   471     updateEditor();
       
   472 }
       
   473 
       
   474 
       
   475 
       
   476 void HbInputPredictionHandlerPrivate::mouseHandler(int cursorPosition, QMouseEvent* mouseEvent)
       
   477 {
       
   478     Q_Q(HbInputPredictionHandler);
       
   479     // we are missing something we must get out.
       
   480     if (!mEngine && !mInputMethod->focusObject()) {
       
   481         return;
       
   482     }
       
   483 
       
   484     // mouse move / hover events needs to be ignored.
       
   485     if (mouseEvent->type() != QEvent::MouseButtonPress) {
       
   486         return;
       
   487     }
       
   488 
       
   489     //The mouse has been clicked outside of the pre-editing word and hence need to commit the word.
       
   490     if ( cursorPosition < 0 || (mCandidates->size()>0 && cursorPosition >= mCandidates->at(mBestGuessLocation).length())) {
       
   491         if (mEngine->inputLength() > 0 && mCandidates->count() > 0 && mBestGuessLocation < mCandidates->count()) {
       
   492             commit(mCandidates->at(mBestGuessLocation),true);
       
   493         }
       
   494     } else if (mCandidates->size() > 0) {
       
   495         if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {
       
   496 			// mouse has been clicked on the pre-editing string ends with "?"
       
   497             //Remove the "?" mark
       
   498             (*mCandidates)[mBestGuessLocation].chop(1);
       
   499             updateEditor();
       
   500             q->processCustomWord((*mCandidates)[mBestGuessLocation]);
       
   501             mCanContinuePrediction = true;
       
   502         } else {
       
   503 
       
   504         //The mouse has been clicked on the pre-editing word, launch candidate list
       
   505         mInputMethod->launchCandidatePopup(*mCandidates);
       
   506         }	
       
   507     }
       
   508 }
       
   509 
       
   510 void HbInputPredictionHandlerPrivate::init()
       
   511 {
       
   512     HbInputLanguage language = HbInputSettingProxy::instance()->globalInputLanguage();
       
   513     mEngine = HbPredictionFactory::instance()->predictionEngineForLanguage(language.language());
       
   514     if (mEngine) {
       
   515         mCandidates = new QStringList();
       
   516     }
       
   517 }
       
   518 
       
   519 void HbInputPredictionHandlerPrivate::reset()
       
   520 {
       
   521     if (mEngine) {
       
   522         mEngine->clear();
       
   523     }
       
   524     if (mCandidates) {
       
   525         mCandidates->clear();
       
   526     }
       
   527 
       
   528     mTailShowing = false;
       
   529 }
       
   530 
       
   531 void HbInputPredictionHandlerPrivate::commit()
       
   532 {
       
   533     if (mEngine && mEngine->inputLength() > 0 && mCandidates->count() > 0) {
       
   534         if(!mCanContinuePrediction) {
       
   535             //Remove the "?" mark
       
   536             (*mCandidates)[mBestGuessLocation].chop(1);
       
   537         }
       
   538 		
       
   539 		// Close exact word pop up in qwerty when the word is committed
       
   540 		if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
       
   541 			mInputMethod->closeExactWordPopup();
       
   542 		}
       
   543 		
       
   544         QString commitString;
       
   545         if(mCandidates->count() <= mBestGuessLocation) {
       
   546             commitString = mCandidates->at(0);
       
   547         } else if (mShowTail == false) {
       
   548             commitString = mCandidates->at(mBestGuessLocation).left(mEngine->inputLength());
       
   549         } else {
       
   550             commitString = mCandidates->at(mBestGuessLocation);
       
   551         }
       
   552         // need to update the freq information
       
   553         mEngine->commit(commitString);
       
   554         commit(commitString,false);
       
   555     }
       
   556 }
       
   557 
       
   558 /*!
       
   559 This function accepts a Qstring and commits the string to editor. This also clears all the key presses and
       
   560 candidates from prediction engine
       
   561 */
       
   562 void HbInputPredictionHandlerPrivate::commit(const QString& string, bool addToUsedWordDict, bool isAsync)
       
   563 {
       
   564     Q_Q(HbInputPredictionHandler);
       
   565     if(!mCanContinuePrediction) {
       
   566         //Remove the "?" mark
       
   567         (*mCandidates)[mBestGuessLocation].chop(1);
       
   568     }
       
   569 
       
   570 	// Close exact word pop up in qwerty when the word is committed
       
   571 	if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
       
   572 		mInputMethod->closeExactWordPopup();
       
   573 	}
       
   574 
       
   575     q->commitAndUpdate(string, 0, 0, isAsync);
       
   576 
       
   577     if(mEngine) {
       
   578         if(addToUsedWordDict && !string.isEmpty()) {
       
   579             QString separator = " ";
       
   580             QStringList stringList = string.split(separator, QString::SkipEmptyParts);
       
   581             foreach (QString str, stringList) {
       
   582                 mEngine->addUsedWord(str);
       
   583             }
       
   584         }
       
   585         mEngine->clear();
       
   586     }
       
   587 
       
   588     //Enable the flag after commit
       
   589     mCanContinuePrediction = true;
       
   590 	mTailShowing = false;
       
   591 }
       
   592 
       
   593 /*!
       
   594 This function accepts a QInputMethodEvent and commits the event to editor. This also clears all the key presses and
       
   595 candidates from prediction engine
       
   596 Warning: Use this only when you want to commit some string to editor. If you want to send some formating information 
       
   597 to editor, use sendAndUpdate(QInputMethodEvent & event); The reason is that, this commit function cleans prediction
       
   598 engine state also.
       
   599 */
       
   600 void HbInputPredictionHandlerPrivate::commit(QInputMethodEvent & event,bool addToUsedWordDict)
       
   601 {
       
   602     Q_Q(HbInputPredictionHandler);
       
   603 
       
   604 	// Close exact word pop up in qwerty when the word is committed
       
   605 	if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
       
   606 		mInputMethod->closeExactWordPopup();
       
   607 	}
       
   608 
       
   609     q->sendAndUpdate(event);
       
   610 
       
   611     if(mEngine) {
       
   612         if(addToUsedWordDict && !event.commitString().isEmpty())
       
   613             mEngine->addUsedWord(event.commitString());
       
   614         mEngine->clear();
       
   615     }
       
   616 
       
   617     //Enable the flag after commit
       
   618     mCanContinuePrediction = true;
       
   619 	mTailShowing = false;
       
   620 
       
   621 }
       
   622 
       
   623 void HbInputPredictionHandlerPrivate::commitExactWord()
       
   624 {
       
   625     if (mEngine && mEngine->inputLength() /*> 0 && mCandidates->count() > 0*/) {
       
   626         commit(mCandidates->at(0), true);
       
   627     }
       
   628 }
       
   629 
       
   630 /*!
       
   631 This function checks if the constructed candidate list is empty and if so, then 
       
   632 appends a "?" mark to the best guessed candidate with put the current key input.
       
   633 */
       
   634 void HbInputPredictionHandlerPrivate::handleEmptyCandidateList()
       
   635 {
       
   636     if (!mCandidates->count()) {
       
   637         QString existingWord(mEngine->currentWord());
       
   638         int lastKeyCode = 0;
       
   639         int lastCharacterCode = 0;
       
   640         bool isCustomWord = false;
       
   641         if(existingWord.length()) {
       
   642             lastCharacterCode = existingWord[existingWord.length()-1].unicode();
       
   643         }
       
   644         const HbKeymap* keymap = HbKeymapFactory::instance()->keymap(HbInputSettingProxy::instance()->globalInputLanguage());
       
   645         if(keymap) {
       
   646             const HbMappedKey* lastKey = keymap->keyForKeycode(mInputMethod->inputState().keyboard(), lastCharacterCode);
       
   647             if (lastKey) {
       
   648                 lastKeyCode = lastKey->keycode.unicode();
       
   649             }
       
   650         }
       
   651         //Temporarily delete the key press
       
   652         mEngine->deleteKeyPress();
       
   653         mEngine->updateCandidates(mBestGuessLocation, isCustomWord);
       
   654         if (mCandidates->count()){
       
   655             (*mCandidates)[mBestGuessLocation].append("?");
       
   656         } else {
       
   657             //Should the mBestGuessLocation not be zero. 
       
   658             mBestGuessLocation = 0;
       
   659             mCandidates->append(mEngine->currentWord());
       
   660             (*mCandidates)[mBestGuessLocation].append("?");
       
   661         }
       
   662         //Now again append the same key press
       
   663         if (lastKeyCode) {
       
   664             mEngine->appendKeyPress(lastKeyCode, mModifiers, mInputMethod->inputState().textCase(), this);
       
   665         } else {
       
   666             mEngine->appendKeyPress(lastCharacterCode, mModifiers, mInputMethod->inputState().textCase(), this);
       
   667         }
       
   668         mCanContinuePrediction = false;
       
   669     } else {
       
   670         mCanContinuePrediction = true;
       
   671     }
       
   672 }
       
   673 
       
   674 HbInputPredictionHandler::HbInputPredictionHandler(HbInputPredictionHandlerPrivate &dd, HbInputAbstractMethod* inputMethod)
       
   675 :HbInputModeHandler(dd, inputMethod)
       
   676 {
       
   677     Q_D(HbInputPredictionHandler);
       
   678     d->q_ptr = this;
       
   679     d->init();
       
   680 }
       
   681 
       
   682 
       
   683 HbInputPredictionHandler::~HbInputPredictionHandler()
       
   684 {
       
   685 }
       
   686 
       
   687 /*!
       
   688     Mouse handler
       
   689 */
       
   690 void HbInputPredictionHandler::mouseHandler(int cursorPosition, QMouseEvent* mouseEvent)
       
   691 {
       
   692     Q_D(HbInputPredictionHandler);
       
   693     d->mouseHandler(cursorPosition, mouseEvent);
       
   694 }
       
   695 
       
   696 /*!
       
   697     Action Handler
       
   698 */
       
   699 bool HbInputPredictionHandler::actionHandler(HbInputModeAction action)
       
   700 {
       
   701     Q_D(HbInputPredictionHandler);
       
   702     bool ret = true;
       
   703     switch (action) {
       
   704         case HbInputModeActionReset: {
       
   705             //At the moment we are commiting the text with the autocompletion part as it needs to be committed on clicking outside the editor. 
       
   706             //TO DO : When We back to the application by pressing Application key the inline word should not commit and remain in the inline editing
       
   707             //d->mShowTail = false;
       
   708             d->commit();
       
   709             d->reset();
       
   710         }
       
   711         break;
       
   712         case HbInputModeActionFocusLost: {
       
   713             // if focus lost happens and before that if toolitip is available then typing line word should be committed in the editor 
       
   714             // if tooltip and autocompletion part is available then typing line word should be committed in the editor along with the autocompletion part            
       
   715             // Focus change should commit the auto-completed part as well.
       
   716             d->commit();
       
   717         }
       
   718             break;
       
   719         case HbInputModeActionCommit: {
       
   720             d->commit();
       
   721         }
       
   722         break;
       
   723         case HbInputModeActionDeleteAndCommit: {
       
   724             deleteOneCharacter();
       
   725             d->commit();
       
   726         }
       
   727         break;
       
   728         case HbInputModeActionSetCandidateList: {
       
   729             if (d->mEngine) {
       
   730                 d->mEngine->setCandidateList(d->mCandidates);
       
   731             } else {
       
   732                 ret = false;
       
   733             }
       
   734         }
       
   735         break;
       
   736         case HbInputModeActionSetKeypad: {
       
   737             if (d->mEngine) {
       
   738                 d->mEngine->setKeyboard(d->mInputMethod->inputState().keyboard());
       
   739             } else {
       
   740                 ret = false;;
       
   741             }
       
   742         }
       
   743         break;
       
   744         case HbInputModeActionLaunchCandidatePopup:
       
   745             if (d->mEngine && d->mCandidates->size()) {
       
   746                 d->mInputMethod->launchCandidatePopup(*d->mCandidates);
       
   747             } else {
       
   748                 ret = false;
       
   749             }
       
   750             break;
       
   751         case HbInputModeActionSecondaryLanguageChanged:
       
   752             if (d->mEngine) {
       
   753                 d->mEngine->setSecondaryLanguage(HbInputSettingProxy::instance()->globalSecondaryInputLanguage());
       
   754             }
       
   755             break;
       
   756         case HbInputModeActionPrimaryLanguageChanged:
       
   757             if(!d->mEngine) {
       
   758                 d->init();
       
   759             }
       
   760             if (d->mEngine) {
       
   761                 d->mEngine->setLanguage(HbInputSettingProxy::instance()->globalInputLanguage());
       
   762             }
       
   763             break;
       
   764         case HbInputModeActionHideTail:
       
   765             d->mShowTail = false;
       
   766             break;
       
   767         default:
       
   768             ret = HbInputModeHandler::actionHandler(action);
       
   769         break;
       
   770     }
       
   771     
       
   772     return ret;
       
   773 }
       
   774 
       
   775 /*!
       
   776     returs the true if we have something in in-line editing.
       
   777 */
       
   778 bool HbInputPredictionHandler::isComposing()
       
   779 {
       
   780     Q_D(HbInputPredictionHandler);
       
   781     if (d->mEngine && d->mEngine->inputLength()>0) {
       
   782         return true;
       
   783     }
       
   784     return false;
       
   785 }
       
   786 
       
   787 /*!
       
   788     SLOT to receive input candidate popup close events.
       
   789 */
       
   790 void HbInputPredictionHandler::candidatePopupClosed(QString activatedText, int closingKey)
       
   791 {
       
   792     Q_D(HbInputPredictionHandler);
       
   793     d->candidatePopupClosed(closingKey, activatedText);
       
   794 }
       
   795 
       
   796 /*!
       
   797     SLOT to receive input qwery dialog box events.
       
   798 */
       
   799 void HbInputPredictionHandler::inputQueryPopupClosed(QString activatedWord, int closingKey)
       
   800 {
       
   801     Q_UNUSED(activatedWord);
       
   802     Q_UNUSED(closingKey);
       
   803 }
       
   804 
       
   805 /*!
       
   806     Appends a unicode character and updates the candidates and editor.
       
   807 */
       
   808 void HbInputPredictionHandler::appendUnicodeCharacter(QChar character)
       
   809 {
       
   810     Q_D(HbInputPredictionHandler);
       
   811     d->keyHandlerUnicode(character);
       
   812 }
       
   813 
       
   814 /*!
       
   815     returns supported languages in current engine.
       
   816 */
       
   817 QList<HbInputLanguage> HbInputPredictionHandler::supportedLanguages() const
       
   818 {
       
   819     Q_D(const HbInputPredictionHandler);
       
   820     if (d->mEngine) {
       
   821        return d->mEngine->languages();
       
   822     }
       
   823 
       
   824     return QList<HbInputLanguage>();
       
   825 }
       
   826 
       
   827 /*!
       
   828     filterEvent function to handler key events.
       
   829 */
       
   830 bool HbInputPredictionHandler::filterEvent(const QKeyEvent * event)
       
   831 {
       
   832     Q_D(HbInputPredictionHandler);
       
   833     return d->filterEvent(event);
       
   834 }
       
   835 
       
   836 /*!
       
   837     this SLOT is called when a character in sct is selected.
       
   838 */
       
   839 void HbInputPredictionHandler::sctCharacterSelected(QString character)
       
   840 {
       
   841     Q_D(HbInputPredictionHandler);
       
   842 	//d->mShowTail = false;
       
   843     d->commit();
       
   844     HbInputModeHandler::sctCharacterSelected(character);
       
   845 }
       
   846 
       
   847 void HbInputPredictionHandler::smileySelected(QString smiley)
       
   848 {
       
   849     Q_D(HbInputPredictionHandler);
       
   850     d->commit();
       
   851     HbInputModeHandler::smileySelected(smiley);
       
   852 }
       
   853 /*!
       
   854     this function commits current pre-edit and adds a character at the end.
       
   855 */
       
   856 void HbInputPredictionHandler::commitAndAppendCharacter(QChar character)
       
   857 {
       
   858     Q_D(HbInputPredictionHandler);
       
   859     d->commitAndAppendCharacter(character);
       
   860 }
       
   861 
       
   862 /*!
       
   863     this function deletes one character and updates the engine and editor.
       
   864 */
       
   865 void HbInputPredictionHandler::deleteOneCharacter()
       
   866 {
       
   867     Q_D(HbInputPredictionHandler);
       
   868     d->deleteOneCharacter();
       
   869 }
       
   870 
       
   871 void HbInputPredictionHandler::commitExactWord()
       
   872 {
       
   873     Q_D(HbInputPredictionHandler);
       
   874     d->commitExactWord();
       
   875 }
       
   876 
       
   877 /*!
       
   878  * A virtual function called by the HbInputPredictionHandler when there is a exact word found
       
   879  * and needs to to handled. Called with an empty string when there is no exact word found.
       
   880  */
       
   881 void HbInputPredictionHandler::processExactWord(QString exactWord)
       
   882 {
       
   883     Q_UNUSED(exactWord);
       
   884 }
       
   885 
       
   886 void HbInputPredictionHandler::processCustomWord(QString customWord)
       
   887 {
       
   888     Q_UNUSED(customWord);
       
   889 }
       
   890 
       
   891 void HbInputPredictionHandler::showExactWordPopupIfNeeded()
       
   892 {
       
   893     Q_D(HbInputPredictionHandler);
       
   894     d->showExactWordPopupIfNeeded();
       
   895 }
       
   896 // EOF