diff -r 730c025d4b77 -r f378acbc9cfb src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp --- a/src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp Thu Jul 15 14:03:49 2010 +0100 +++ b/src/hbplugins/inputmethods/common/hbinputpredictionhandler.cpp Thu Jul 22 16:36:53 2010 +0100 @@ -39,17 +39,17 @@ #include "hbinputpredictionhandler_p.h" #include "hbinputabstractbase.h" -#define HbDeltaHeight 3.0 +static const qreal HbDeltaHeight = 3.0; HbInputPredictionHandlerPrivate::HbInputPredictionHandlerPrivate() :mEngine(0), mCandidates(0), mBestGuessLocation(0), mShowTail(true), - mTailShowing(false), mAutoAddedSpace(true), mCanContinuePrediction(true), - mShowTooltip(true) + mShowTooltip(true), + mSpellQueryDialog(0) { } @@ -63,13 +63,17 @@ void HbInputPredictionHandlerPrivate::deleteOneCharacter() { + if (!mEngine && !mInputMethod->focusObject()) { + return; + } 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 ) { - //Only autocomplition part should be deleted when autocompliton part is enable and user pressed a delete key - if(false == mTailShowing) { + int tailLength = mInputMethod->focusObject()->preEditString().length() - mEngine->inputLength(); + //Only autocomplition part should be deleted when autocompliton part is shown and user pressed a delete key + if(tailLength <= 0) { // no autocompletion part displayed mEngine->deleteKeyPress( this ); } //To prevent showing autocompletion part while deleting the characters using backspace key @@ -112,16 +116,8 @@ 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)); - } + commitString = getCommitString(); + mEngine->addUsedWord(commitString); if (character == QChar(' ') || character == QChar('\n')) { mAutoAddedSpace = true; } @@ -167,14 +163,6 @@ */ 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 HbInputPredictionHandlerPrivate::probableKeypresses() @@ -222,16 +210,21 @@ QBrush brush(col); QTextCharFormat gray; gray.setForeground(brush); - list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, mEngine->inputLength(), taillength, gray)); + if((focusedObject->object())->inherits("QGraphicsWebView") || (focusedObject->object())->inherits("QWebView")) { + //QGraphicsWebView does not handle partial input length formatting well. Causes crash, a temporary fix provided, + //This makes the whole text field grey insted of just the auto-completion part. Anyways, it does not cause crash. + //This should be treated as a work around till QGraphicsWebView is fixed. + list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, QInputMethodEvent::TextFormat, gray)); + } else { + 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())) { @@ -252,7 +245,8 @@ 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)) { + if(!focusObject || event->key() < 0 || + event->key() == HbInputButton::ButtonKeyCodeCustom) { return false; } @@ -280,59 +274,16 @@ } 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 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 HbInputButton::ButtonKeyCodeEnter: case HbInputButton::ButtonKeyCodeSpace: - 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 @@ -415,18 +366,15 @@ } //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); - } + if ( cursorPosition < 0 || cursorPosition >= mInputMethod->focusObject()->preEditString().length()) { + commit(); } else if (mCandidates->size() > 0) { if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) { - // mouse has been clicked on the pre-editing string ends with "?" + // 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; + q->launchSpellQueryDialog(); } else { //The mouse has been clicked on the pre-editing word, launch candidate list @@ -437,7 +385,7 @@ void HbInputPredictionHandlerPrivate::init() { - mEngine = NULL; + mEngine = 0; HbInputLanguage language = HbInputSettingProxy::instance()->globalInputLanguage(); mEngine = HbPredictionFactory::instance()->predictionEngineForLanguage(language.language()); if (mEngine && !mCandidates) { @@ -453,24 +401,33 @@ 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; + QString commitString = getCommitString(); + + // need to update the freq information + mEngine->commit(commitString); + commit(commitString,false); + } +} + +QString HbInputPredictionHandlerPrivate::getCommitString() +{ + QString commitString; + if(mCandidates->count()) { + if(!mCanContinuePrediction) { + //Remove the "?" mark + (*mCandidates)[mBestGuessLocation].chop(1); + } if(mCandidates->count() <= mBestGuessLocation) { commitString = mCandidates->at(0); } else if (mShowTail == false) { @@ -478,10 +435,8 @@ } else { commitString = mCandidates->at(mBestGuessLocation); } - // need to update the freq information - mEngine->commit(commitString); - commit(commitString,false); } + return commitString; } /*! @@ -491,12 +446,8 @@ 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 + // Close exact word pop up in qwerty when the word is committed if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { mInputMethod->closeExactWordPopup(); } @@ -505,9 +456,9 @@ if(mEngine) { if(addToUsedWordDict && !string.isEmpty()) { - QString separator = " "; - QStringList stringList = string.split(separator, QString::SkipEmptyParts); - foreach (QString str, stringList) { + QChar spaceChar(' '); + QStringList stringList = string.split(spaceChar, QString::SkipEmptyParts); + foreach (const QString str, stringList) { mEngine->addUsedWord(str); } } @@ -516,7 +467,6 @@ //Enable the flag after commit mCanContinuePrediction = true; - mTailShowing = false; } /*! @@ -545,8 +495,6 @@ //Enable the flag after commit mCanContinuePrediction = true; - mTailShowing = false; - } void HbInputPredictionHandlerPrivate::commitExactWord() @@ -601,6 +549,21 @@ } } +void HbInputPredictionHandlerPrivate::setPreEditTextToEditor(QString string, bool showAutocompletionPart) +{ + //update the editor with pre-edit text + mEngine->setWord(string); + bool used = false; + mEngine->updateCandidates(mBestGuessLocation, used); + if(showAutocompletionPart) { + mShowTail = true; + } else { + mShowTail = false; + } + updateEditor(); + +} + HbInputPredictionHandler::HbInputPredictionHandler(HbInputPredictionHandlerPrivate &dd, HbInputAbstractMethod* inputMethod) :HbInputModeHandler(dd, inputMethod) { @@ -631,25 +594,16 @@ 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. + case HbInputModeActionReset: + case HbInputModeActionCommit: + case HbInputModeActionFocusLost: { + //At the moment we are committing 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(); @@ -694,9 +648,12 @@ case HbInputModeActionHideTail: d->mShowTail = false; break; + case HbInputModeActionCloseSpellQuery: + closeSpellQueryDialog(); + break; default: ret = HbInputModeHandler::actionHandler(action); - break; + break; } return ret; @@ -813,14 +770,106 @@ Q_UNUSED(exactWord); } -void HbInputPredictionHandler::processCustomWord(QString customWord) -{ - Q_UNUSED(customWord); -} - void HbInputPredictionHandler::showExactWordPopupIfNeeded() { Q_D(HbInputPredictionHandler); d->showExactWordPopupIfNeeded(); } + +// Launch spell query dialog in responce to launchSpellQueryDialog signal +void HbInputPredictionHandler::launchSpellQueryDialog() +{ + Q_D(HbInputPredictionHandler); + HbInputFocusObject *focusedObject = d->mInputMethod->focusObject(); + if(!focusedObject) { + return; + } + + // As of now we need to delete and create mSpellQueryDialog every time + // we launch it. If we launch the same dialog, keypad does not open sometimes. + // Will take sometime to find out the root cause of this, and will fix this. + if(d->mSpellQueryDialog) { + delete d->mSpellQueryDialog; + d->mSpellQueryDialog =0; + } + if(!d->mSpellQueryDialog) { + d->mSpellQueryDialog = new HbInputSpellQuery(d->mInputMethod,this); + d->mSpellQueryDialog->setParent(this); + } + + QString string; + if(d->mCandidates && (*(d->mCandidates)).size() >= d->mBestGuessLocation + 1) { + string = (*(d->mCandidates))[d->mBestGuessLocation].left(d->mEngine->inputLength()); + } + d->reset(); + d->mSpellQueryDialog->launch(string); + +} + +// To force the spell query dialog to close. +void HbInputPredictionHandler::closeSpellQueryDialog() +{ + Q_D(HbInputPredictionHandler); + if (d->mSpellQueryDialog && d->mSpellQueryDialog->isVisible()) { + d->mSpellQueryDialog->close(); + } +} + +// +void HbInputPredictionHandler::spellQueryDialogClosed(QObject *savedFocusObject + ,HbInputSpellQuery::HbSpellCloseReason closeReason,const QString &string) +{ + if(!savedFocusObject) { + return; + } + + Q_D(HbInputPredictionHandler); + // set the focus back to the editor which caused the launch of spell dialog. + HbInputFocusObject *newFocusObject = new HbInputFocusObject(savedFocusObject); + newFocusObject->releaseFocus(); + newFocusObject->setFocus(); + HbAbstractEdit *abstractEdit = qobject_cast(savedFocusObject); + if(abstractEdit) { + abstractEdit->setCursorPosition(abstractEdit->cursorPosition()); + } + d->mInputMethod->setFocusObject(newFocusObject); + + if (closeReason == HbInputSpellQuery::HbOkPressed) { + d->commit(string,true); + } else if(closeReason == HbInputSpellQuery::HbCancelPressed) { + //update the editor with pre-edit text + d->setPreEditTextToEditor(string, d->mCanContinuePrediction); + // This update is need for below usecase + // Editor is empty => enter some data till their is no match => click on word + // to launch spell query => now press cancel => testcase of keypad is uppercase, + // but it should be lower case + d->mInputMethod->updateState(); + } else if (closeReason == HbInputSpellQuery::HbForceClose) { + // Force spell query close happens when oriantation is about to change. + // In this case nomal commit() on input method does not seems to work. + // So we are directly sending commit even to editor. + QList list; + QInputMethodEvent event(QString(), list); + event.setCommitString(string); + QApplication::sendEvent(savedFocusObject, &event); + } + // Enable the flag + d->mCanContinuePrediction = true; +} + + +void HbInputPredictionHandler::setAutocompletionStatus(bool status) +{ + Q_D(HbInputPredictionHandler); + d->mAutocompletionEnabled = status; + if(!d->mEngine) { + return; + } + if(!status) { + d->mEngine->disableFeature(HbPredFeatureWordCompletion); + } else { + d->mEngine->enableFeature(HbPredFeatureWordCompletion); + } + +} // EOF