src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,896 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbPlugins module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+#include <QTextCharFormat>
+#include <hbinputpredictionengine.h>
+#include <hbinputsettingproxy.h>
+#include <hbinputpredictionfactory.h>
+#include <hbinputkeymap.h>
+#include <hbinputkeymapfactory.h>
+#include <hbinputdialog.h>
+#include <hbaction.h>
+#include <hbinputvkbhost.h>
+#include <hbcolorscheme.h>
+#include <hbinpututils.h>
+#include "../touchinput/virtualqwerty.h"
+
+#include "hbinputpredictionhandler_p.h"
+#include "hbinputabstractbase.h"
+
+#define HbDeltaHeight 3.0
+
+HbInputPredictionHandlerPrivate::HbInputPredictionHandlerPrivate()
+    :mEngine(0),
+    mCandidates(0),
+    mBestGuessLocation(0),
+    mShowTail(true),
+    mTailShowing(false),
+    mAutoAddedSpace(true),
+    mCanContinuePrediction(true),
+    mShowTooltip(true)
+{
+}
+
+HbInputPredictionHandlerPrivate::~HbInputPredictionHandlerPrivate()
+{
+    if (mCandidates) {
+        delete mCandidates;
+        mCandidates = 0;
+    }
+}
+
+void HbInputPredictionHandlerPrivate::deleteOneCharacter()
+{
+    mShowTail = true;
+    mShowTooltip = true;
+    // A backspace in predictive means updating the engine for the delete key press
+    // and get the new candidate list from the engine.
+    if ((mEngine->inputLength() >= 1) || selectWord()) {
+        //Only autocomplition part should be deleted when autocompliton part is enable and user pressed a delete key
+        if(false == mTailShowing) {
+            mEngine->deleteKeyPress( this );
+        }
+        //To prevent showing autocompletion part while deleting the characters using backspace key
+        mShowTail = false;
+        mShowTooltip = false;
+		if (mEngine->inputLength() > 0) {
+            bool unused = false;
+            mEngine->updateCandidates(mBestGuessLocation, unused);
+            if (!mCandidates->count()) {
+                mCandidates->append(mEngine->currentWord());
+            }
+		}
+		mCanContinuePrediction = true;
+		// update the editor with the new preedit text.
+        updateEditor();
+        return;
+    }
+
+    HbInputFocusObject* focusedObject = 0;
+    focusedObject = mInputMethod->focusObject();
+    if (!focusedObject) {
+        return;
+    }
+
+    if ((focusedObject->inputMethodQuery(Qt::ImCursorPosition).toInt() >= 0) || focusedObject->preEditString().length()) {
+        QList<QInputMethodEvent::Attribute> list;
+        QInputMethodEvent event(QString(), list);
+        event.setCommitString(QString(), -1, 1);
+        commit(event);
+    }
+}
+
+void HbInputPredictionHandlerPrivate::commitAndAppendCharacter(QChar character)
+{
+    if (!mEngine) {
+        return;
+    }
+
+    HbInputFocusObject* focusedObject = 0;
+    focusedObject = mInputMethod->focusObject();
+    if (!focusedObject) {
+        return;
+    }
+
+    QString commitString;
+    if (mEngine->inputLength() > 0 && mCandidates->count() > 0) {
+        if(mCandidates->count() <= mBestGuessLocation) {
+            commitString = mCandidates->at(0);
+            mEngine->addUsedWord(mCandidates->at(0));
+        } else if (mShowTail == false) {
+            commitString = mCandidates->at(mBestGuessLocation).left(mEngine->inputLength());
+            mEngine->addUsedWord(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()));
+        } else {
+            commitString = mCandidates->at(mBestGuessLocation);
+            mEngine->addUsedWord(mCandidates->at(mBestGuessLocation));
+        }
+        if (character == QChar(' ') || character == QChar('\n')) {
+            mAutoAddedSpace = true;
+        }
+        commit(commitString);
+    } else {
+        mAutoAddedSpace = false;
+    }
+    commitString = character;
+    commit(commitString);
+}
+
+/*!
+Commits the candidate upon closing of the candidate list. Now can the closing key be anything other than
+just selection. Need to evaluate this. When the candidate list is visible, the current implementation of the
+candidate list does not allow the virtual keypad to be clicked.
+*/
+void HbInputPredictionHandlerPrivate::candidatePopupClosed(int closingKey, const QString& activatedText)
+{
+    if (!mEngine) {
+        return;
+    }
+
+    HbInputFocusObject* focusedObject = 0;
+    focusedObject = mInputMethod->focusObject();
+    if (!focusedObject) {
+        return;
+    }
+
+    QString commitString  = activatedText;
+    if (closingKey == Qt::Key_0 || closingKey == Qt::Key_Space) {
+        commitString = activatedText+' ';
+    } else if (closingKey == Qt::Key_Enter || closingKey == Qt::Key_Return) {
+        commitString = activatedText;
+        commit(commitString);
+        commitString = '\n';
+    }
+
+    commit(commitString,true);
+}
+
+/*!
+This function shows the exact popup if needed.
+*/
+void HbInputPredictionHandlerPrivate::showExactWordPopupIfNeeded()
+{
+    Q_Q(HbInputPredictionHandler);
+    if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \
+        != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) {                
+        q->processExactWord(mCandidates->at(0));
+    } else {
+        QString empty;
+        q->processExactWord(empty);
+    }
+}
+
+QList<HbKeyPressProbability> HbInputPredictionHandlerPrivate::probableKeypresses()
+{
+    if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
+        //Useof the concrete input method implementations make the modehandlersin flexible.
+        //Later an intermediate abstract class needsto be introduced.
+        HbVirtualQwerty * qwertyInputMethod = qobject_cast<HbVirtualQwerty*>(mInputMethod);
+        if(qwertyInputMethod) {
+            return qwertyInputMethod->probableKeypresses();
+        }
+    }
+    return QList<HbKeyPressProbability>();
+}
+
+/*!
+This sets the selected candidate from the candidate list as the editor text.
+*/
+bool HbInputPredictionHandlerPrivate::selectWord(bool selectFromLeft)
+{
+    if (!mEngine) {
+        return false;
+    }
+    mShowTail = false;
+
+    HbInputFocusObject* focusedObject = 0;
+    focusedObject = mInputMethod->focusObject();
+    if(!focusedObject) {
+        return false;
+    }
+    // No word selected, if we move next to a word on left side, select it
+    int cursorPos = focusedObject->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+    QString text = focusedObject->inputMethodQuery(Qt::ImSurroundingText).toString();
+    if ((cursorPos > 0 && selectFromLeft) || (cursorPos < text.length() && !selectFromLeft)) {
+        int start;
+        int end;
+        if (selectFromLeft && cursorPos>=1 &&!text.at(cursorPos-1).isSpace()) {
+            // selecting word from left side of cursor
+            end = cursorPos;
+            for(start = end; start > 0; start--) {
+                if (text.at(start-1).isSpace()) {
+                    break;
+                }
+            }
+        } else if (!selectFromLeft && !text.at(cursorPos).isSpace()) {
+            // selecting word from right side of cursor
+            start = cursorPos;
+            for(end = start; end < text.length(); ++end) {
+                if (text.at(end).isSpace()) {
+                    break;
+                }
+            }
+        } else {
+            // no word in the direction where cursor is moving
+            return false;
+        }
+        int length = end-start;
+        // update internal state and editor
+        if(length > 0){
+            mEngine->setWord(text.mid(start, length), this);
+        }
+        bool unused = false;
+        mEngine->updateCandidates(mBestGuessLocation, unused);
+        //With selection we can always continue predicting, even when the selection 
+        //is not a well predicted word.
+        if (!mCandidates->count()) {
+            //Here we are making sure that even if the engine does not return any candidate
+            //for given input sequence, the candidate list is non-empty. In such a scenario
+            //the candidate list will contain the actual selection or the exact word.
+            mCandidates->append(mEngine->currentWord());
+        }
+        //
+        QTextCharFormat underlined;
+        QList<QInputMethodEvent::Attribute> list;
+        underlined.setFontUnderline(true);
+        QInputMethodEvent::Attribute textstyle(QInputMethodEvent::TextFormat, 0, mEngine->inputLength(), underlined);
+        list.append(textstyle);
+        QInputMethodEvent event(mCandidates->at(0), list);
+        event.setCommitString(QString(), (selectFromLeft ? -length : 0), length);
+        focusedObject->sendEvent(event);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/*!
+This method updates the editor contents based on the candidates available in the candidate list.
+*/
+void HbInputPredictionHandlerPrivate::updateEditor()
+{
+    Q_Q(HbInputPredictionHandler);
+    if (!mEngine) {
+        return;
+    }
+
+    QList<QInputMethodEvent::Attribute> list;
+    QTextCharFormat underlined;
+    HbInputFocusObject *focusedObject = 0;
+    underlined.setFontUnderline(true);
+    QInputMethodEvent::Attribute textstyle(QInputMethodEvent::TextFormat, 0, mEngine->inputLength(), underlined);
+    list.append(textstyle);
+
+    focusedObject = mInputMethod->focusObject();
+    Q_ASSERT(focusedObject);
+
+    if (mEngine->inputLength() == 0) {
+        QInputMethodEvent event(QString(), list);
+        q->sendAndUpdate(event);
+    } else {
+        if (mCandidates->count() > mBestGuessLocation) {
+            int taillength = mCandidates->at(mBestGuessLocation).length() - mEngine->inputLength();
+            if (taillength > 0 && mShowTail) {
+                // TODO: Color from skin should be used
+				QColor col = HbColorScheme::color("qtc_editor_hint_normal");
+                QBrush brush(col);
+                QTextCharFormat gray;
+                gray.setForeground(brush);
+                list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, mEngine->inputLength(), taillength, gray));
+				list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mEngine->inputLength(), 0, 0));
+                QInputMethodEvent event(mCandidates->at(mBestGuessLocation), list);
+                focusedObject->sendEvent(event);
+                mTailShowing = true;
+            } else {
+				list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mCandidates->at(mBestGuessLocation).length(), 0, 0));
+                QInputMethodEvent event(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()), list);
+                focusedObject->sendEvent(event);
+                mTailShowing = false;
+            }
+            if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \
+                != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) {                
+                    q->processExactWord(mCandidates->at(0));
+            } else {
+                QString empty;
+                q->processExactWord(empty);
+            }
+        } else {
+            QInputMethodEvent event(QString(""), list);
+            focusedObject->sendEvent(event);
+        }
+    }
+}
+
+bool HbInputPredictionHandlerPrivate::filterEvent(const QKeyEvent * event)
+{
+    HbInputFocusObject* focusObject = 0;
+    focusObject = mInputMethod->focusObject();
+    //If the focused object is NULL or the key event is improper, can not continue
+    if(!focusObject || (event->key()<0)) {
+        return false;
+    }
+
+    Q_Q(HbInputPredictionHandler);
+    if (!mEngine) {
+        return false;
+    }
+
+    bool ret = false;
+    mModifiers = Qt::NoModifier;   
+    mCanContinuePrediction = true;
+    switch (event->key()) {
+    case Qt::Key_Backspace:
+    case Qt::Key_Delete:
+        {
+            QString currentSelection = focusObject->inputMethodQuery(Qt::ImCurrentSelection).toString();
+            if(currentSelection.length()) {
+                QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);		
+                q->sendAndUpdate(event);
+                event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier);
+                q->sendAndUpdate(event);
+            } else {
+                deleteOneCharacter();
+            }
+		}
+        ret = true;
+        break;
+    case Qt::Key_Period: // TODO: better handling for punctuation
+    case Qt::Key_Comma: { // Need to take fn, shift etc. in account
+            HbModifier modifier = HbModifierNone;
+            int currentTextCase = focusObject->editorInterface().textCase();
+            if ( HbTextCaseUpper == currentTextCase || HbTextCaseAutomatic == currentTextCase ) {
+                modifier = HbModifierShiftPressed;
+            }
+            QString qc;
+            const HbMappedKey* mappedKey = mKeymap->keyForKeycode(mInputMethod->inputState().keyboard(), event->key());
+
+            if (mappedKey) {
+                if (modifier == HbModifierNone) {
+                    qc = mappedKey->characters(HbModifierNone).left(1);
+                } else if (modifier == HbModifierShiftPressed) {
+                    qc = mappedKey->characters(HbModifierShiftPressed).left(1);
+                }
+            }
+
+            if (mEngine->inputLength() == 0) {
+                QList<QInputMethodEvent::Attribute> list;
+                QInputMethodEvent event(QString(), list);
+                if (mAutoAddedSpace) {
+                    int cursorPos = mInputMethod->focusObject()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+                    QString text = mInputMethod->focusObject()->inputMethodQuery(Qt::ImSurroundingText).toString();
+                    if (cursorPos > 0 && text.at(cursorPos-1).isSpace()) {
+                        event.setCommitString(qc, -1, 1);
+                    } else {
+                        event.setCommitString(qc);
+                    }
+                } else {
+                    event.setCommitString(qc);
+                }
+                mAutoAddedSpace = false;
+                q->sendAndUpdate(event);
+            } else {
+                // Fix for input stopping after ,. keys in qwerty predictive
+                commitAndAppendCharacter(qc.at(0));
+                QString empty;
+                q->processExactWord(empty);
+            }
+            ret = true;
+        }
+        break;
+    case Qt::Key_Return:
+    case Qt::Key_Enter:
+    case Qt::Key_Space:
+    case Qt::Key_0: {//Space
+            // A space means we have to commit the candidates when we are in predictive mode.
+            QChar qc(event->key());
+            if (qc == Qt::Key_Enter) {
+                qc = QChar('\n');  // Editor expects normal line feed.
+            } else if (qc == Qt::Key_0) {
+                qc = QChar(' ');
+            }
+            commitAndAppendCharacter(qc);
+            // if exact word popup functionality is on then we should inform exact word popup
+            // about the space.//++TODO
+            QString empty;
+            q->processExactWord(empty);
+            ret = true;
+        }
+        break;
+    default: {
+            mShowTail = true;
+            mShowTooltip = true;
+            mAutoAddedSpace = false;
+            if (q->HbInputModeHandler::filterEvent(event)) {
+                return true;
+            }
+            if (mEngine) {
+                int currentTextCase = focusObject->editorInterface().textCase();
+                if ( HbTextCaseUpper == currentTextCase || HbTextCaseAutomatic == currentTextCase ) {
+                    mModifiers |= Qt::ShiftModifier;
+                }
+                mEngine->appendKeyPress(event->key(), mModifiers, mInputMethod->inputState().textCase(), this);
+                bool isCustomWord = false;
+                mEngine->updateCandidates(mBestGuessLocation, isCustomWord);
+                //The engine can not predict the word, it is a custom word. Now engine returns a
+                //single candidate entry which is actually the previous properly predicted character.
+                //TODO: In such a scenario, the prediction should stop and there needs to be some way for
+                //the user to tell the correct word which he wants (Some query editor). But, such a thing is
+                //not in place and hence the current implementation just appends a "?" and displays the
+                //previous word itself.
+                if (isCustomWord && mCandidates->count()) {
+                    QString replacementText = mCandidates->at(0);//+"?";
+                    mCandidates->clear();
+                    mCandidates->append(replacementText);
+                    //Since there is only one candidate, that's the best prediction.
+                    mBestGuessLocation = 0;
+                }
+                //We need to check and carry out necessary steps if the engine fails to predict any candidate,
+                //for the give input sequence.
+                handleEmptyCandidateList();
+                updateEditor();
+                mInputMethod->updateState();
+                ret = true;
+            }
+        }
+    }
+
+    return ret;
+}
+
+void HbInputPredictionHandlerPrivate::keyHandlerUnicode(const QChar& character)
+{
+    if (!mEngine) {
+        return;
+    }
+    mEngine->appendCharacter(character, mInputMethod->inputState().textCase(), this);
+    bool unused = false;
+    mEngine->updateCandidates(mBestGuessLocation, unused);
+    //Check if the candidate list is empty and take necessary steps if so.
+    handleEmptyCandidateList();
+    updateEditor();
+}
+
+
+
+void HbInputPredictionHandlerPrivate::mouseHandler(int cursorPosition, QMouseEvent* mouseEvent)
+{
+    Q_Q(HbInputPredictionHandler);
+    // we are missing something we must get out.
+    if (!mEngine && !mInputMethod->focusObject()) {
+        return;
+    }
+
+    // mouse move / hover events needs to be ignored.
+    if (mouseEvent->type() != QEvent::MouseButtonPress) {
+        return;
+    }
+
+    //The mouse has been clicked outside of the pre-editing word and hence need to commit the word.
+    if ( cursorPosition < 0 || (mCandidates->size()>0 && cursorPosition >= mCandidates->at(mBestGuessLocation).length())) {
+        if (mEngine->inputLength() > 0 && mCandidates->count() > 0 && mBestGuessLocation < mCandidates->count()) {
+            commit(mCandidates->at(mBestGuessLocation),true);
+        }
+    } else if (mCandidates->size() > 0) {
+        if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {
+			// mouse has been clicked on the pre-editing string ends with "?"
+            //Remove the "?" mark
+            (*mCandidates)[mBestGuessLocation].chop(1);
+            updateEditor();
+            q->processCustomWord((*mCandidates)[mBestGuessLocation]);
+            mCanContinuePrediction = true;
+        } else {
+
+        //The mouse has been clicked on the pre-editing word, launch candidate list
+        mInputMethod->launchCandidatePopup(*mCandidates);
+        }	
+    }
+}
+
+void HbInputPredictionHandlerPrivate::init()
+{
+    HbInputLanguage language = HbInputSettingProxy::instance()->globalInputLanguage();
+    mEngine = HbPredictionFactory::instance()->predictionEngineForLanguage(language.language());
+    if (mEngine) {
+        mCandidates = new QStringList();
+    }
+}
+
+void HbInputPredictionHandlerPrivate::reset()
+{
+    if (mEngine) {
+        mEngine->clear();
+    }
+    if (mCandidates) {
+        mCandidates->clear();
+    }
+
+    mTailShowing = false;
+}
+
+void HbInputPredictionHandlerPrivate::commit()
+{
+    if (mEngine && mEngine->inputLength() > 0 && mCandidates->count() > 0) {
+        if(!mCanContinuePrediction) {
+            //Remove the "?" mark
+            (*mCandidates)[mBestGuessLocation].chop(1);
+        }
+		
+		// Close exact word pop up in qwerty when the word is committed
+		if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
+			mInputMethod->closeExactWordPopup();
+		}
+		
+        QString commitString;
+        if(mCandidates->count() <= mBestGuessLocation) {
+            commitString = mCandidates->at(0);
+        } else if (mShowTail == false) {
+            commitString = mCandidates->at(mBestGuessLocation).left(mEngine->inputLength());
+        } else {
+            commitString = mCandidates->at(mBestGuessLocation);
+        }
+        // need to update the freq information
+        mEngine->commit(commitString);
+        commit(commitString,false);
+    }
+}
+
+/*!
+This function accepts a Qstring and commits the string to editor. This also clears all the key presses and
+candidates from prediction engine
+*/
+void HbInputPredictionHandlerPrivate::commit(const QString& string, bool addToUsedWordDict, bool isAsync)
+{
+    Q_Q(HbInputPredictionHandler);
+    if(!mCanContinuePrediction) {
+        //Remove the "?" mark
+        (*mCandidates)[mBestGuessLocation].chop(1);
+    }
+
+	// Close exact word pop up in qwerty when the word is committed
+	if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
+		mInputMethod->closeExactWordPopup();
+	}
+
+    q->commitAndUpdate(string, 0, 0, isAsync);
+
+    if(mEngine) {
+        if(addToUsedWordDict && !string.isEmpty()) {
+            QString separator = " ";
+            QStringList stringList = string.split(separator, QString::SkipEmptyParts);
+            foreach (QString str, stringList) {
+                mEngine->addUsedWord(str);
+            }
+        }
+        mEngine->clear();
+    }
+
+    //Enable the flag after commit
+    mCanContinuePrediction = true;
+	mTailShowing = false;
+}
+
+/*!
+This function accepts a QInputMethodEvent and commits the event to editor. This also clears all the key presses and
+candidates from prediction engine
+Warning: Use this only when you want to commit some string to editor. If you want to send some formating information 
+to editor, use sendAndUpdate(QInputMethodEvent & event); The reason is that, this commit function cleans prediction
+engine state also.
+*/
+void HbInputPredictionHandlerPrivate::commit(QInputMethodEvent & event,bool addToUsedWordDict)
+{
+    Q_Q(HbInputPredictionHandler);
+
+	// Close exact word pop up in qwerty when the word is committed
+	if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) {
+		mInputMethod->closeExactWordPopup();
+	}
+
+    q->sendAndUpdate(event);
+
+    if(mEngine) {
+        if(addToUsedWordDict && !event.commitString().isEmpty())
+            mEngine->addUsedWord(event.commitString());
+        mEngine->clear();
+    }
+
+    //Enable the flag after commit
+    mCanContinuePrediction = true;
+	mTailShowing = false;
+
+}
+
+void HbInputPredictionHandlerPrivate::commitExactWord()
+{
+    if (mEngine && mEngine->inputLength() /*> 0 && mCandidates->count() > 0*/) {
+        commit(mCandidates->at(0), true);
+    }
+}
+
+/*!
+This function checks if the constructed candidate list is empty and if so, then 
+appends a "?" mark to the best guessed candidate with put the current key input.
+*/
+void HbInputPredictionHandlerPrivate::handleEmptyCandidateList()
+{
+    if (!mCandidates->count()) {
+        QString existingWord(mEngine->currentWord());
+        int lastKeyCode = 0;
+        int lastCharacterCode = 0;
+        bool isCustomWord = false;
+        if(existingWord.length()) {
+            lastCharacterCode = existingWord[existingWord.length()-1].unicode();
+        }
+        const HbKeymap* keymap = HbKeymapFactory::instance()->keymap(HbInputSettingProxy::instance()->globalInputLanguage());
+        if(keymap) {
+            const HbMappedKey* lastKey = keymap->keyForKeycode(mInputMethod->inputState().keyboard(), lastCharacterCode);
+            if (lastKey) {
+                lastKeyCode = lastKey->keycode.unicode();
+            }
+        }
+        //Temporarily delete the key press
+        mEngine->deleteKeyPress();
+        mEngine->updateCandidates(mBestGuessLocation, isCustomWord);
+        if (mCandidates->count()){
+            (*mCandidates)[mBestGuessLocation].append("?");
+        } else {
+            //Should the mBestGuessLocation not be zero. 
+            mBestGuessLocation = 0;
+            mCandidates->append(mEngine->currentWord());
+            (*mCandidates)[mBestGuessLocation].append("?");
+        }
+        //Now again append the same key press
+        if (lastKeyCode) {
+            mEngine->appendKeyPress(lastKeyCode, mModifiers, mInputMethod->inputState().textCase(), this);
+        } else {
+            mEngine->appendKeyPress(lastCharacterCode, mModifiers, mInputMethod->inputState().textCase(), this);
+        }
+        mCanContinuePrediction = false;
+    } else {
+        mCanContinuePrediction = true;
+    }
+}
+
+HbInputPredictionHandler::HbInputPredictionHandler(HbInputPredictionHandlerPrivate &dd, HbInputAbstractMethod* inputMethod)
+:HbInputModeHandler(dd, inputMethod)
+{
+    Q_D(HbInputPredictionHandler);
+    d->q_ptr = this;
+    d->init();
+}
+
+
+HbInputPredictionHandler::~HbInputPredictionHandler()
+{
+}
+
+/*!
+    Mouse handler
+*/
+void HbInputPredictionHandler::mouseHandler(int cursorPosition, QMouseEvent* mouseEvent)
+{
+    Q_D(HbInputPredictionHandler);
+    d->mouseHandler(cursorPosition, mouseEvent);
+}
+
+/*!
+    Action Handler
+*/
+bool HbInputPredictionHandler::actionHandler(HbInputModeAction action)
+{
+    Q_D(HbInputPredictionHandler);
+    bool ret = true;
+    switch (action) {
+        case HbInputModeActionReset: {
+            //At the moment we are commiting the text with the autocompletion part as it needs to be committed on clicking outside the editor. 
+            //TO DO : When We back to the application by pressing Application key the inline word should not commit and remain in the inline editing
+            //d->mShowTail = false;
+            d->commit();
+            d->reset();
+        }
+        break;
+        case HbInputModeActionFocusLost: {
+            // if focus lost happens and before that if toolitip is available then typing line word should be committed in the editor 
+            // if tooltip and autocompletion part is available then typing line word should be committed in the editor along with the autocompletion part            
+            // Focus change should commit the auto-completed part as well.
+            d->commit();
+        }
+            break;
+        case HbInputModeActionCommit: {
+            d->commit();
+        }
+        break;
+        case HbInputModeActionDeleteAndCommit: {
+            deleteOneCharacter();
+            d->commit();
+        }
+        break;
+        case HbInputModeActionSetCandidateList: {
+            if (d->mEngine) {
+                d->mEngine->setCandidateList(d->mCandidates);
+            } else {
+                ret = false;
+            }
+        }
+        break;
+        case HbInputModeActionSetKeypad: {
+            if (d->mEngine) {
+                d->mEngine->setKeyboard(d->mInputMethod->inputState().keyboard());
+            } else {
+                ret = false;;
+            }
+        }
+        break;
+        case HbInputModeActionLaunchCandidatePopup:
+            if (d->mEngine && d->mCandidates->size()) {
+                d->mInputMethod->launchCandidatePopup(*d->mCandidates);
+            } else {
+                ret = false;
+            }
+            break;
+        case HbInputModeActionSecondaryLanguageChanged:
+            if (d->mEngine) {
+                d->mEngine->setSecondaryLanguage(HbInputSettingProxy::instance()->globalSecondaryInputLanguage());
+            }
+            break;
+        case HbInputModeActionPrimaryLanguageChanged:
+            if(!d->mEngine) {
+                d->init();
+            }
+            if (d->mEngine) {
+                d->mEngine->setLanguage(HbInputSettingProxy::instance()->globalInputLanguage());
+            }
+            break;
+        case HbInputModeActionHideTail:
+            d->mShowTail = false;
+            break;
+        default:
+            ret = HbInputModeHandler::actionHandler(action);
+        break;
+    }
+    
+    return ret;
+}
+
+/*!
+    returs the true if we have something in in-line editing.
+*/
+bool HbInputPredictionHandler::isComposing()
+{
+    Q_D(HbInputPredictionHandler);
+    if (d->mEngine && d->mEngine->inputLength()>0) {
+        return true;
+    }
+    return false;
+}
+
+/*!
+    SLOT to receive input candidate popup close events.
+*/
+void HbInputPredictionHandler::candidatePopupClosed(QString activatedText, int closingKey)
+{
+    Q_D(HbInputPredictionHandler);
+    d->candidatePopupClosed(closingKey, activatedText);
+}
+
+/*!
+    SLOT to receive input qwery dialog box events.
+*/
+void HbInputPredictionHandler::inputQueryPopupClosed(QString activatedWord, int closingKey)
+{
+    Q_UNUSED(activatedWord);
+    Q_UNUSED(closingKey);
+}
+
+/*!
+    Appends a unicode character and updates the candidates and editor.
+*/
+void HbInputPredictionHandler::appendUnicodeCharacter(QChar character)
+{
+    Q_D(HbInputPredictionHandler);
+    d->keyHandlerUnicode(character);
+}
+
+/*!
+    returns supported languages in current engine.
+*/
+QList<HbInputLanguage> HbInputPredictionHandler::supportedLanguages() const
+{
+    Q_D(const HbInputPredictionHandler);
+    if (d->mEngine) {
+       return d->mEngine->languages();
+    }
+
+    return QList<HbInputLanguage>();
+}
+
+/*!
+    filterEvent function to handler key events.
+*/
+bool HbInputPredictionHandler::filterEvent(const QKeyEvent * event)
+{
+    Q_D(HbInputPredictionHandler);
+    return d->filterEvent(event);
+}
+
+/*!
+    this SLOT is called when a character in sct is selected.
+*/
+void HbInputPredictionHandler::sctCharacterSelected(QString character)
+{
+    Q_D(HbInputPredictionHandler);
+	//d->mShowTail = false;
+    d->commit();
+    HbInputModeHandler::sctCharacterSelected(character);
+}
+
+void HbInputPredictionHandler::smileySelected(QString smiley)
+{
+    Q_D(HbInputPredictionHandler);
+    d->commit();
+    HbInputModeHandler::smileySelected(smiley);
+}
+/*!
+    this function commits current pre-edit and adds a character at the end.
+*/
+void HbInputPredictionHandler::commitAndAppendCharacter(QChar character)
+{
+    Q_D(HbInputPredictionHandler);
+    d->commitAndAppendCharacter(character);
+}
+
+/*!
+    this function deletes one character and updates the engine and editor.
+*/
+void HbInputPredictionHandler::deleteOneCharacter()
+{
+    Q_D(HbInputPredictionHandler);
+    d->deleteOneCharacter();
+}
+
+void HbInputPredictionHandler::commitExactWord()
+{
+    Q_D(HbInputPredictionHandler);
+    d->commitExactWord();
+}
+
+/*!
+ * A virtual function called by the HbInputPredictionHandler when there is a exact word found
+ * and needs to to handled. Called with an empty string when there is no exact word found.
+ */
+void HbInputPredictionHandler::processExactWord(QString exactWord)
+{
+    Q_UNUSED(exactWord);
+}
+
+void HbInputPredictionHandler::processCustomWord(QString customWord)
+{
+    Q_UNUSED(customWord);
+}
+
+void HbInputPredictionHandler::showExactWordPopupIfNeeded()
+{
+    Q_D(HbInputPredictionHandler);
+    d->showExactWordPopupIfNeeded();
+}
+// EOF