32 #include <hbaction.h> |
32 #include <hbaction.h> |
33 #include <hbinputvkbhost.h> |
33 #include <hbinputvkbhost.h> |
34 #include <hbcolorscheme.h> |
34 #include <hbcolorscheme.h> |
35 #include <hbinpututils.h> |
35 #include <hbinpututils.h> |
36 #include <hbinputbutton.h> |
36 #include <hbinputbutton.h> |
|
37 #include <hbmainwindow.h> |
|
38 |
37 #include "../touchinput/virtualqwerty.h" |
39 #include "../touchinput/virtualqwerty.h" |
38 |
40 |
39 #include "hbinputpredictionhandler_p.h" |
41 #include "hbinputpredictionhandler_p.h" |
40 #include "hbinputabstractbase.h" |
42 #include "hbinputabstractbase.h" |
41 |
|
42 static const qreal HbDeltaHeight = 3.0; |
|
43 |
43 |
44 HbInputPredictionHandlerPrivate::HbInputPredictionHandlerPrivate() |
44 HbInputPredictionHandlerPrivate::HbInputPredictionHandlerPrivate() |
45 :mEngine(0), |
45 :mEngine(0), |
46 mCandidates(0), |
46 mCandidates(0), |
47 mBestGuessLocation(0), |
47 mBestGuessLocation(0), |
77 mEngine->deleteKeyPress( this ); |
80 mEngine->deleteKeyPress( this ); |
78 } |
81 } |
79 //To prevent showing autocompletion part while deleting the characters using backspace key |
82 //To prevent showing autocompletion part while deleting the characters using backspace key |
80 mShowTail = false; |
83 mShowTail = false; |
81 mShowTooltip = false; |
84 mShowTooltip = false; |
82 bool unused = false; |
85 bool unused = false; |
83 mEngine->updateCandidates(mBestGuessLocation, unused); |
86 mEngine->updateCandidates(mBestGuessLocation, unused); |
84 //If Input length greater or equal to one then Append the current word to candidate |
87 //If Input length greater or equal to one then Append the current word to candidate |
85 if (!mCandidates->count() && mEngine->inputLength() >= 1) { |
88 if (!mCandidates->count() && mEngine->inputLength() >= 1) { |
86 mCandidates->append(mEngine->currentWord()); |
89 mCandidates->append(mEngine->currentWord()); |
87 } |
90 } |
88 mCanContinuePrediction = true; |
91 mCanContinuePrediction = true; |
89 // update the editor with the new preedit text. |
92 // update the editor with the new preedit text. |
90 updateEditor(); |
93 updateEditor(); |
91 return; |
94 return; |
92 } else { |
95 } else { |
93 // we come here if their is no data in engine. |
96 // we come here if their is no data in engine. |
94 // once the word is committed, we can not bring it back to inline edit. |
97 // once the word is committed, we can not bring it back to inline edit. |
95 // so if the engine does not have any data, we just send backspace event to the editor. |
98 // so if the engine does not have any data, we just send backspace event to the editor. |
96 Q_Q(HbInputPredictionHandler); |
99 Q_Q(HbInputPredictionHandler); |
97 QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); |
100 QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); |
98 q->sendAndUpdate(event); |
101 q->sendAndUpdate(event); |
99 event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier); |
102 event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier); |
100 q->sendAndUpdate(event); |
103 q->sendAndUpdate(event); |
101 return; |
104 return; |
102 } |
105 } |
204 } else { |
207 } else { |
205 if (mCandidates->count() > mBestGuessLocation) { |
208 if (mCandidates->count() > mBestGuessLocation) { |
206 int taillength = mCandidates->at(mBestGuessLocation).length() - mEngine->inputLength(); |
209 int taillength = mCandidates->at(mBestGuessLocation).length() - mEngine->inputLength(); |
207 if (taillength > 0 && mShowTail) { |
210 if (taillength > 0 && mShowTail) { |
208 // TODO: Color from skin should be used |
211 // TODO: Color from skin should be used |
209 QColor col = HbColorScheme::color("qtc_input_hint_normal"); |
212 QColor col = HbColorScheme::color("qtc_input_hint_normal"); |
210 QBrush brush(col); |
213 QBrush brush(col); |
211 QTextCharFormat gray; |
214 QTextCharFormat gray; |
212 gray.setForeground(brush); |
215 gray.setForeground(brush); |
213 if((focusedObject->object())->inherits("QGraphicsWebView") || (focusedObject->object())->inherits("QWebView")) { |
216 if((focusedObject->object())->inherits("QGraphicsWebView") || (focusedObject->object())->inherits("QWebView")) { |
214 //QGraphicsWebView does not handle partial input length formatting well. Causes crash, a temporary fix provided, |
217 //QGraphicsWebView does not handle partial input length formatting well. Causes crash, a temporary fix provided, |
216 //This should be treated as a work around till QGraphicsWebView is fixed. |
219 //This should be treated as a work around till QGraphicsWebView is fixed. |
217 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, QInputMethodEvent::TextFormat, gray)); |
220 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, QInputMethodEvent::TextFormat, gray)); |
218 } else { |
221 } else { |
219 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, mEngine->inputLength(), taillength, gray)); |
222 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, mEngine->inputLength(), taillength, gray)); |
220 } |
223 } |
221 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mEngine->inputLength(), 0, 0)); |
224 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mEngine->inputLength(), 0, 0)); |
222 QInputMethodEvent event(mCandidates->at(mBestGuessLocation), list); |
225 QInputMethodEvent event(mCandidates->at(mBestGuessLocation), list); |
223 focusedObject->sendEvent(event); |
226 focusedObject->sendEvent(event); |
224 } else { |
227 } else { |
225 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mCandidates->at(mBestGuessLocation).length(), 0, 0)); |
228 list.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, mCandidates->at(mBestGuessLocation).length(), 0, 0)); |
226 QInputMethodEvent event(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()), list); |
229 QInputMethodEvent event(mCandidates->at(mBestGuessLocation).left(mEngine->inputLength()), list); |
227 focusedObject->sendEvent(event); |
230 focusedObject->sendEvent(event); |
228 } |
231 } |
229 if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \ |
232 if (mShowTooltip && mBestGuessLocation > 0 && mCandidates->at(0).mid(0, mEngine->inputLength()) \ |
230 != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) { |
233 != mCandidates->at(mBestGuessLocation).mid(0, mEngine->inputLength())) { |
262 case Qt::Key_Backspace: |
265 case Qt::Key_Backspace: |
263 case HbInputButton::ButtonKeyCodeDelete: |
266 case HbInputButton::ButtonKeyCodeDelete: |
264 { |
267 { |
265 QString currentSelection = focusObject->inputMethodQuery(Qt::ImCurrentSelection).toString(); |
268 QString currentSelection = focusObject->inputMethodQuery(Qt::ImCurrentSelection).toString(); |
266 if(currentSelection.length()) { |
269 if(currentSelection.length()) { |
267 QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); |
270 QKeyEvent event = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier); |
268 q->sendAndUpdate(event); |
271 q->sendAndUpdate(event); |
269 event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier); |
272 event = QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier); |
270 q->sendAndUpdate(event); |
273 q->sendAndUpdate(event); |
271 } else { |
274 } else { |
272 deleteOneCharacter(); |
275 deleteOneCharacter(); |
273 } |
276 } |
274 } |
277 } |
275 ret = true; |
278 ret = true; |
276 break; |
279 break; |
277 |
280 |
278 case HbInputButton::ButtonKeyCodeEnter: |
281 case HbInputButton::ButtonKeyCodeEnter: |
279 case HbInputButton::ButtonKeyCodeSpace: |
282 case HbInputButton::ButtonKeyCodeSpace: |
377 q->launchSpellQueryDialog(); |
383 q->launchSpellQueryDialog(); |
378 } else { |
384 } else { |
379 |
385 |
380 //The mouse has been clicked on the pre-editing word, launch candidate list |
386 //The mouse has been clicked on the pre-editing word, launch candidate list |
381 mInputMethod->launchCandidatePopup(*mCandidates); |
387 mInputMethod->launchCandidatePopup(*mCandidates); |
382 } |
388 } |
383 } |
389 } |
384 } |
390 } |
385 |
391 |
386 void HbInputPredictionHandlerPrivate::init() |
392 void HbInputPredictionHandlerPrivate::init() |
387 { |
393 { |
388 mEngine = 0; |
394 mEngine = 0; |
389 HbInputLanguage language = HbInputSettingProxy::instance()->globalInputLanguage(); |
395 HbInputLanguage language = mInputMethod->inputState().language(); |
390 mEngine = HbPredictionFactory::instance()->predictionEngineForLanguage(language.language()); |
396 if(!language.language()) { |
|
397 language = HbInputSettingProxy::instance()->globalInputLanguage(); |
|
398 } |
|
399 mEngine = HbPredictionFactory::instance()->predictionEngineForLanguage(language.language()); |
391 if (mEngine && !mCandidates) { |
400 if (mEngine && !mCandidates) { |
392 mCandidates = new QStringList(); |
401 mCandidates = new QStringList(); |
393 } |
402 } |
394 } |
403 } |
395 |
404 |
404 } |
413 } |
405 |
414 |
406 void HbInputPredictionHandlerPrivate::commit() |
415 void HbInputPredictionHandlerPrivate::commit() |
407 { |
416 { |
408 if (mEngine && mEngine->inputLength() > 0 && mCandidates->count() > 0) { |
417 if (mEngine && mEngine->inputLength() > 0 && mCandidates->count() > 0) { |
409 |
418 |
410 // Close exact word pop up in qwerty when the word is committed |
419 // Close exact word pop up in qwerty when the word is committed |
411 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
420 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
412 mInputMethod->closeExactWordPopup(); |
421 mInputMethod->closeExactWordPopup(); |
413 } |
422 } |
414 |
423 |
415 QString commitString = getCommitString(); |
424 QString commitString = getCommitString(); |
416 |
425 |
417 // need to update the freq information |
426 // need to update the freq information |
418 mEngine->commit(commitString); |
427 mEngine->commit(commitString); |
419 commit(commitString,false); |
428 commit(commitString,false); |
446 void HbInputPredictionHandlerPrivate::commit(const QString& string, bool addToUsedWordDict, bool isAsync) |
455 void HbInputPredictionHandlerPrivate::commit(const QString& string, bool addToUsedWordDict, bool isAsync) |
447 { |
456 { |
448 Q_Q(HbInputPredictionHandler); |
457 Q_Q(HbInputPredictionHandler); |
449 |
458 |
450 // Close exact word pop up in qwerty when the word is committed |
459 // Close exact word pop up in qwerty when the word is committed |
451 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
460 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
452 mInputMethod->closeExactWordPopup(); |
461 mInputMethod->closeExactWordPopup(); |
453 } |
462 } |
454 |
|
455 q->commitAndUpdate(string, 0, 0, isAsync); |
|
456 |
463 |
457 if(mEngine) { |
464 if(mEngine) { |
458 if(addToUsedWordDict && !string.isEmpty()) { |
465 if(addToUsedWordDict && !string.isEmpty()) { |
459 QChar spaceChar(' '); |
466 QChar spaceChar(' '); |
460 QStringList stringList = string.split(spaceChar, QString::SkipEmptyParts); |
467 QStringList stringList = string.split(spaceChar, QString::SkipEmptyParts); |
478 */ |
486 */ |
479 void HbInputPredictionHandlerPrivate::commit(QInputMethodEvent & event,bool addToUsedWordDict) |
487 void HbInputPredictionHandlerPrivate::commit(QInputMethodEvent & event,bool addToUsedWordDict) |
480 { |
488 { |
481 Q_Q(HbInputPredictionHandler); |
489 Q_Q(HbInputPredictionHandler); |
482 |
490 |
483 // Close exact word pop up in qwerty when the word is committed |
491 // Close exact word pop up in qwerty when the word is committed |
484 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
492 if(HbInputUtils::isQwertyKeyboard(mInputMethod->inputState().keyboard())) { |
485 mInputMethod->closeExactWordPopup(); |
493 mInputMethod->closeExactWordPopup(); |
486 } |
494 } |
487 |
495 |
488 q->sendAndUpdate(event); |
496 q->sendAndUpdate(event); |
489 |
497 |
490 if(mEngine) { |
498 if(mEngine) { |
491 if(addToUsedWordDict && !event.commitString().isEmpty()) |
499 if(addToUsedWordDict && !event.commitString().isEmpty()) |
527 } |
535 } |
528 //Temporarily delete the key press |
536 //Temporarily delete the key press |
529 mEngine->deleteKeyPress(); |
537 mEngine->deleteKeyPress(); |
530 mEngine->updateCandidates(mBestGuessLocation, isCustomWord); |
538 mEngine->updateCandidates(mBestGuessLocation, isCustomWord); |
531 if (mCandidates->count()){ |
539 if (mCandidates->count()){ |
532 (*mCandidates)[mBestGuessLocation] = (*mCandidates)[mBestGuessLocation].left(mEngine->inputLength()); |
540 (*mCandidates)[mBestGuessLocation] = (*mCandidates)[mBestGuessLocation].left(mEngine->inputLength()); |
533 (*mCandidates)[mBestGuessLocation].append("?"); |
541 (*mCandidates)[mBestGuessLocation].append("?"); |
534 } else { |
542 } else { |
535 //Should the mBestGuessLocation not be zero. |
543 //Should the mBestGuessLocation not be zero. |
536 mBestGuessLocation = 0; |
544 mBestGuessLocation = 0; |
537 mCandidates->append(mEngine->currentWord()); |
545 mCandidates->append(mEngine->currentWord()); |
551 |
559 |
552 void HbInputPredictionHandlerPrivate::setPreEditTextToEditor(QString string, bool showAutocompletionPart) |
560 void HbInputPredictionHandlerPrivate::setPreEditTextToEditor(QString string, bool showAutocompletionPart) |
553 { |
561 { |
554 //update the editor with pre-edit text |
562 //update the editor with pre-edit text |
555 mEngine->setWord(string); |
563 mEngine->setWord(string); |
556 bool used = false; |
564 bool used = false; |
557 mEngine->updateCandidates(mBestGuessLocation, used); |
565 mEngine->updateCandidates(mBestGuessLocation, used); |
558 if(showAutocompletionPart) { |
566 if(showAutocompletionPart && mShowTail) { |
559 mShowTail = true; |
567 mShowTail = true; |
560 } else { |
568 } else { |
561 mShowTail = false; |
569 mShowTail = false; |
562 } |
570 } |
563 updateEditor(); |
571 updateEditor(); |
724 this SLOT is called when a character in sct is selected. |
735 this SLOT is called when a character in sct is selected. |
725 */ |
736 */ |
726 void HbInputPredictionHandler::sctCharacterSelected(QString character) |
737 void HbInputPredictionHandler::sctCharacterSelected(QString character) |
727 { |
738 { |
728 Q_D(HbInputPredictionHandler); |
739 Q_D(HbInputPredictionHandler); |
729 //d->mShowTail = false; |
740 //d->mShowTail = false; |
730 d->commit(); |
741 d->commit(); |
731 HbInputModeHandler::sctCharacterSelected(character); |
742 HbInputModeHandler::sctCharacterSelected(character); |
732 } |
743 } |
733 |
744 |
734 void HbInputPredictionHandler::smileySelected(QString smiley) |
745 void HbInputPredictionHandler::smileySelected(QString smiley) |
782 Q_D(HbInputPredictionHandler); |
793 Q_D(HbInputPredictionHandler); |
783 HbInputFocusObject *focusedObject = d->mInputMethod->focusObject(); |
794 HbInputFocusObject *focusedObject = d->mInputMethod->focusObject(); |
784 if(!focusedObject) { |
795 if(!focusedObject) { |
785 return; |
796 return; |
786 } |
797 } |
|
798 |
|
799 //store the secondary language |
|
800 d->mSecLanguage = HbInputSettingProxy::instance()->globalSecondaryInputLanguage(); |
787 |
801 |
788 // As of now we need to delete and create mSpellQueryDialog every time |
802 // As of now we need to delete and create mSpellQueryDialog every time |
789 // we launch it. If we launch the same dialog, keypad does not open sometimes. |
803 // we launch it. If we launch the same dialog, keypad does not open sometimes. |
790 // Will take sometime to find out the root cause of this, and will fix this. |
804 // Will take sometime to find out the root cause of this, and will fix this. |
791 if(d->mSpellQueryDialog) { |
805 if(d->mSpellQueryDialog) { |
792 delete d->mSpellQueryDialog; |
806 delete d->mSpellQueryDialog; |
793 d->mSpellQueryDialog =0; |
807 d->mSpellQueryDialog =0; |
794 } |
808 } |
795 if(!d->mSpellQueryDialog) { |
809 if(!d->mSpellQueryDialog) { |
796 d->mSpellQueryDialog = new HbInputSpellQuery(d->mInputMethod,this); |
810 d->mSpellQueryDialog = new HbInputSpellQuery(d->mInputMethod,this); |
797 d->mSpellQueryDialog->setParent(this); |
|
798 } |
811 } |
799 |
812 |
800 QString string; |
813 QString string; |
801 if(d->mCandidates && (*(d->mCandidates)).size() >= d->mBestGuessLocation + 1) { |
814 if(d->mCandidates && (*(d->mCandidates)).size() >= d->mBestGuessLocation + 1) { |
802 string = (*(d->mCandidates))[d->mBestGuessLocation].left(d->mEngine->inputLength()); |
815 string = (*(d->mCandidates))[d->mBestGuessLocation].left(d->mEngine->inputLength()); |
803 } |
816 } |
804 d->reset(); |
817 d->reset(); |
|
818 |
|
819 QObject::connect(d->mSpellQueryDialog->mainWindow(), SIGNAL(orientationChanged(Qt::Orientation)), |
|
820 this, SLOT(closeSpellQueryDialog())); |
|
821 |
805 d->mSpellQueryDialog->launch(string); |
822 d->mSpellQueryDialog->launch(string); |
806 |
823 |
807 } |
824 } |
808 |
825 |
809 // To force the spell query dialog to close. |
826 // To force the spell query dialog to close. |
824 } |
841 } |
825 |
842 |
826 Q_D(HbInputPredictionHandler); |
843 Q_D(HbInputPredictionHandler); |
827 // set the focus back to the editor which caused the launch of spell dialog. |
844 // set the focus back to the editor which caused the launch of spell dialog. |
828 HbInputFocusObject *newFocusObject = new HbInputFocusObject(savedFocusObject); |
845 HbInputFocusObject *newFocusObject = new HbInputFocusObject(savedFocusObject); |
|
846 HbInputState savedState; |
|
847 newFocusObject->editorInterface().lastFocusedState(savedState); |
829 newFocusObject->releaseFocus(); |
848 newFocusObject->releaseFocus(); |
830 newFocusObject->setFocus(); |
849 HbInputMethod *activeMethod = HbInputMethod::activeInputMethod(); |
|
850 if(activeMethod->isFocusLocked()) { |
|
851 activeMethod->unlockFocus(); |
|
852 newFocusObject->setFocus(); |
|
853 //By this time the active input method has been changed. |
|
854 HbInputMethod::activeInputMethod()->setFocusObject(newFocusObject); |
|
855 activeMethod->lockFocus(); |
|
856 } else { |
|
857 newFocusObject->setFocus(); |
|
858 HbInputMethod::activeInputMethod()->setFocusObject(newFocusObject); |
|
859 } |
831 HbAbstractEdit *abstractEdit = qobject_cast<HbAbstractEdit*>(savedFocusObject); |
860 HbAbstractEdit *abstractEdit = qobject_cast<HbAbstractEdit*>(savedFocusObject); |
832 if(abstractEdit) { |
861 if(abstractEdit) { |
833 abstractEdit->setCursorPosition(abstractEdit->cursorPosition()); |
862 abstractEdit->setCursorPosition(abstractEdit->cursorPosition()); |
834 } |
863 } |
835 d->mInputMethod->setFocusObject(newFocusObject); |
|
836 |
864 |
837 if (closeReason == HbInputSpellQuery::HbOkPressed) { |
865 if (closeReason == HbInputSpellQuery::HbOkPressed) { |
838 d->commit(string,true); |
866 d->commit(string,true); |
839 } else if(closeReason == HbInputSpellQuery::HbCancelPressed) { |
867 } else if(closeReason == HbInputSpellQuery::HbCancelPressed) { |
840 //update the editor with pre-edit text |
868 if(!HbInputSettingProxy::instance()->predictiveInputStatus(HbKeyboardSetting12key) || savedState.language()!= d->mInputMethod->inputState().language().language() |
841 d->setPreEditTextToEditor(string, d->mCanContinuePrediction); |
869 || d->mSecLanguage != HbInputSettingProxy::instance()->globalSecondaryInputLanguage()) { |
|
870 //This check is for: If user do a prediction off from the input setting or if user change the |
|
871 //language when the spell query is launched and then if user presses cancel |
|
872 //on the spell query then whatever user have already entered |
|
873 //in the inline mode should get commit to the editor. |
|
874 d->commit(string,false); |
|
875 } else { |
|
876 //update the editor with pre-edit text |
|
877 d->setPreEditTextToEditor(string, d->mCanContinuePrediction); |
|
878 } |
842 // This update is need for below usecase |
879 // This update is need for below usecase |
843 // Editor is empty => enter some data till their is no match => click on word |
880 // Editor is empty => enter some data till their is no match => click on word |
844 // to launch spell query => now press cancel => testcase of keypad is uppercase, |
881 // to launch spell query => now press cancel => testcase of keypad is uppercase, |
845 // but it should be lower case |
882 // but it should be lower case |
846 d->mInputMethod->updateState(); |
883 d->mInputMethod->updateState(); |