src/hbplugins/inputmethods/touchinput/hbinputprediction12keyhandler.cpp
changeset 5 627c4a0fd0e7
parent 3 11d3954df52a
child 6 c3690ec91ef8
equal deleted inserted replaced
3:11d3954df52a 5:627c4a0fd0e7
    45 #include "hbinputprediction12keyhandler_p.h"
    45 #include "hbinputprediction12keyhandler_p.h"
    46 
    46 
    47 #define HbDeltaHeight 3.0
    47 #define HbDeltaHeight 3.0
    48 #define MAXUDBWORDSIZE 64
    48 #define MAXUDBWORDSIZE 64
    49 
    49 
    50 HbInputSpellQuery::HbInputSpellQuery(HbInputPrediction12KeyHandlerPrivate *owner) : mOwner(owner), mPrimaryAction(0)
       
    51 {
       
    52 }
       
    53 
       
    54 void HbInputSpellQuery::launch(QString editorText)
       
    55 {
       
    56     HbInputFocusObject *focusObject = mOwner->mInputMethod->focusObject();
       
    57     if (!focusObject) {
       
    58         return;
       
    59     }
       
    60     mSavedState = mOwner->mInputMethod->inputState();
       
    61     mOwner->mEngine->clear();
       
    62     mOwner->mCanContinuePrediction = true;
       
    63     // close the keypad before showing the spell dialog
       
    64     HbVkbHost *vkbHost = focusObject->editorInterface().vkbHost();
       
    65     if (vkbHost && vkbHost->keypadStatus() != HbVkbHost::HbVkbStatusClosed) {
       
    66         vkbHost->closeKeypad();
       
    67     }
       
    68     setInputMode(HbInputDialog::TextInput);
       
    69     setPromptText(tr("Spell:"));
       
    70     setValue(QVariant(editorText));
       
    71 
       
    72     //set the spell dialog position
       
    73     QSizeF  newSize; 
       
    74     QPointF newPos;
       
    75     QRectF newGeometry;
       
    76     getPositionAndSize(newPos, newSize, newGeometry);
       
    77     newGeometry.setHeight(newSize.height());
       
    78     newGeometry.setWidth(newSize.width());
       
    79     setGeometry(newGeometry);
       
    80     setPos(newPos);
       
    81 
       
    82     // change the focus to spell dialog editor
       
    83     HbLineEdit *spellEdit = lineEdit();
       
    84     if (spellEdit) {      
       
    85         spellEdit->setMaxLength(MAXUDBWORDSIZE);
       
    86         spellEdit->setSmileysEnabled(false);
       
    87         HbEditorInterface eInt(spellEdit);
       
    88         // we don't want prediction and automatic textcase in spell query dialog
       
    89         spellEdit->setInputMethodHints(spellEdit->inputMethodHints() | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase);
       
    90         eInt.setLastFocusedState(mSavedState);
       
    91         spellEdit->setFocus();
       
    92     }
       
    93     
       
    94     // execute the spell dialog
       
    95     mSavedFocusObject = focusObject->object();
       
    96     mSavedEditorText = editorText;
       
    97     //setAttribute(Qt::WA_DeleteOnClose);
       
    98     mDidHandleFinish = false;
       
    99     open(this,SLOT(dialogClosed(HbAction*)));
       
   100     mPrimaryAction = qobject_cast<HbAction*>(actions().first());
       
   101 }
       
   102 
       
   103 void HbInputSpellQuery::dialogClosed(HbAction* action)
       
   104 {
       
   105     //There are multiple dialog closed event received. This will make sure we handle finish
       
   106     //only once
       
   107     if(mDidHandleFinish) {
       
   108         return;
       
   109     } else {
       
   110         mDidHandleFinish = true;
       
   111     }
       
   112 	
       
   113     bool isOk = false;
       
   114     bool isCancel = false;
       
   115     bool isExternalClose = false;
       
   116     // action is null when input query is closed externally , for example by calling
       
   117     // HbDialog::close() function.
       
   118     if (action) {
       
   119        isOk = mPrimaryAction == action ? true : false;
       
   120        isCancel = mPrimaryAction != action ? true : false;
       
   121     } else {
       
   122         isExternalClose = true;
       
   123     }
       
   124     
       
   125     //Need to disable effects as asynchronous hide will commit the word otherwise.
       
   126     HbEffect::disable(this);
       
   127     hide();
       
   128     HbEffect::enable(this);  
       
   129 	
       
   130     HbInputFocusObject *newFocusObject = new HbInputFocusObject(mSavedFocusObject);
       
   131     newFocusObject->releaseFocus();
       
   132     newFocusObject->setFocus();
       
   133     
       
   134     HbAbstractEdit *abstractEdit = qobject_cast<HbAbstractEdit*>(mSavedFocusObject);
       
   135     
       
   136     if(abstractEdit) {
       
   137         abstractEdit->setCursorPosition(abstractEdit->cursorPosition());
       
   138     }
       
   139     
       
   140     mOwner->mInputMethod->setFocusObject(newFocusObject);
       
   141     mOwner->mInputMethod->focusObject()->editorInterface().setTextCase(mSavedState.textCase());
       
   142     
       
   143     if (isOk) {
       
   144 		mOwner->commit(value().toString(), true, true);
       
   145 	} else if (isCancel) {
       
   146         //update the editor with pre-edit text
       
   147         mOwner->mEngine->setWord(mSavedEditorText);
       
   148         bool used = false;	 
       
   149         mOwner->mEngine->updateCandidates(mOwner->mBestGuessLocation, used);
       
   150         mOwner->mShowTail = false;
       
   151         mOwner->updateEditor();
       
   152 	} else if (isExternalClose) {
       
   153 		mOwner->commit(mSavedEditorText, true, true);
       
   154 	}
       
   155 	
       
   156 	mSavedEditorText.clear();
       
   157 }
       
   158 
       
   159 void HbInputSpellQuery::getPositionAndSize(QPointF &pos,QSizeF &size, QRectF &geom)
       
   160 {
       
   161     pos = HbInputDialog::pos();
       
   162     size = HbInputDialog::size();
       
   163     geom = HbInputDialog::geometry();
       
   164 
       
   165     QRectF cursorRect = mOwner->mInputMethod->focusObject()->microFocus(); // from the top of the screen
       
   166     pos = QPointF(cursorRect.bottomLeft().x(),cursorRect.bottomLeft().y());
       
   167     qreal heightOfTitlebar = 80.0; // Using magic number for now...
       
   168     qreal screenHeight = (qreal)HbDeviceProfile::current().logicalSize().height();
       
   169 
       
   170     if( ((screenHeight - cursorRect.bottomLeft().y()) > (cursorRect.y() - heightOfTitlebar))
       
   171         || ((screenHeight - cursorRect.bottomLeft().y() + HbDeltaHeight ) > geom.height()) ) {
       
   172         // this means there is amore space below inline text than at the top or we can fit spell Dialog
       
   173         // below inline text
       
   174         pos.setY(cursorRect.bottomLeft().y() + HbDeltaHeight);
       
   175         size.setHeight(screenHeight - pos.y());
       
   176    } else {
       
   177         // this means there is amore space above inline text than below it
       
   178         pos.setY(cursorRect.y() - geom.height() - HbDeltaHeight);
       
   179         if (pos.y() < heightOfTitlebar) {
       
   180             // this means that spell dialog can not be fit in from top of inline text, we need to trim it
       
   181             pos.setY(heightOfTitlebar);
       
   182         }
       
   183         size.setHeight(cursorRect.y() - heightOfTitlebar - HbDeltaHeight);
       
   184     }
       
   185     if ( size.height() > geom.height()) {
       
   186         size.setHeight(geom.height());
       
   187     }
       
   188     if ((pos.x() + size.width()) > (qreal)HbDeviceProfile::current().logicalSize().width()) {
       
   189         // can not fit spell dialog to the right side of inline edit text.
       
   190         pos.setX((qreal)HbDeviceProfile::current().logicalSize().width()- size.width());
       
   191     }
       
   192 }
       
   193 
       
   194 HbInputPrediction12KeyHandlerPrivate::HbInputPrediction12KeyHandlerPrivate()
    50 HbInputPrediction12KeyHandlerPrivate::HbInputPrediction12KeyHandlerPrivate()
   195 :mLastKey(0),
    51 :mLastKey(0),
   196 mButtonDown(false),
    52 mButtonDown(false),
   197 mCurrentChar(0),
    53 mCurrentChar(0),
   198 mLongPressHappened(false),
    54 mLongPressHappened(false),
   199 mShiftKeyDoubleTap(false),
    55 mShiftKeyDoubleTap(false)
   200 mInputSpellQuery(NULL)
       
   201 {
    56 {
   202 }
    57 }
   203 
    58 
   204 HbInputPrediction12KeyHandlerPrivate::~HbInputPrediction12KeyHandlerPrivate()
    59 HbInputPrediction12KeyHandlerPrivate::~HbInputPrediction12KeyHandlerPrivate()
   205 {
    60 {
   206     delete mInputSpellQuery;
       
   207 	mInputSpellQuery = 0;
       
   208 }
    61 }
   209 
    62 
   210 void HbInputPrediction12KeyHandlerPrivate::chopQMarkAndUpdateEditor()
    63 void HbInputPrediction12KeyHandlerPrivate::chopQMarkAndUpdateEditor()
   211 {
    64 {
   212     if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {	
    65     if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {
   213         (*mCandidates)[mBestGuessLocation].chop(1);
    66         (*mCandidates)[mBestGuessLocation].chop(1);
   214         updateEditor();
    67         updateEditor();
   215         mCanContinuePrediction = true;
    68         mCanContinuePrediction = true;
   216     }
    69     }
   217 }
    70 }
   228 
    81 
   229     int buttonId = keyEvent->key();
    82     int buttonId = keyEvent->key();
   230 
    83 
   231     if (keyEvent->isAutoRepeat() && mLastKey == buttonId) {
    84     if (keyEvent->isAutoRepeat() && mLastKey == buttonId) {
   232         if (buttonId == HbInputButton::ButtonKeyCodeAsterisk) {
    85         if (buttonId == HbInputButton::ButtonKeyCodeAsterisk) {
   233             if (!mCanContinuePrediction) {
    86             //Remove the "?" mark if present
   234                 mInputMethod->switchMode(buttonId);
    87             chopQMarkAndUpdateEditor();
   235             } else {
    88             q->actionHandler(HbInputModeHandler::HbInputModeActionCommit);
   236                 //Remove the "?" mark if present
    89             mInputMethod->selectSpecialCharacterTableMode();
   237                 chopQMarkAndUpdateEditor();
       
   238                 mInputMethod->selectSpecialCharacterTableMode();
       
   239             }
       
   240             mLongPressHappened = true;
    90             mLongPressHappened = true;
   241         } else if (buttonId == HbInputButton::ButtonKeyCodeShift) {
    91         } else if (buttonId == HbInputButton::ButtonKeyCodeShift) {
   242             mInputMethod->switchMode(HbInputButton::ButtonKeyCodeShift);
    92             mInputMethod->switchMode(HbInputButton::ButtonKeyCodeShift);
   243             mLongPressHappened = true;
    93             mLongPressHappened = true;
   244         } else if (buttonId == HbInputButton::ButtonKeyCodeSymbol) {
    94         } else if (buttonId == HbInputButton::ButtonKeyCodeSymbol) {
   255             // Delete "?" entered
   105             // Delete "?" entered
   256             if (!mCanContinuePrediction) {
   106             if (!mCanContinuePrediction) {
   257                 deleteOneCharacter();
   107                 deleteOneCharacter();
   258                 mLongPressHappened = true;
   108                 mLongPressHappened = true;
   259             }
   109             }
   260 			if (buttonId != HbInputButton::ButtonKeyCodeDelete) {
   110             if (buttonId != HbInputButton::ButtonKeyCodeDelete) {
   261 				q->commitFirstMappedNumber(buttonId, mInputMethod->currentKeyboardType());
   111                 q->commitFirstMappedNumber(buttonId, mInputMethod->currentKeyboardType());
   262                 mLongPressHappened = true;
   112                 mLongPressHappened = true;
   263 			}
   113             }
   264         }
   114         }
   265 
   115 
   266         if (mLongPressHappened) {
   116         if (mLongPressHappened) {
   267             mLastKey = 0;
   117             mLastKey = 0;
   268             return true;
   118             return true;
   269         }
   119         }
   270     }
   120     }
   271 
   121 
   272     if (buttonId == HbInputButton::ButtonKeyCodeShift) {		
   122     if (buttonId == HbInputButton::ButtonKeyCodeShift) {
   273         // if we get a second consequtive shift key press, 
   123         // if we get a second consequtive shift key press, 
   274         // we want to handle it in buttonRelease
   124         // we want to handle it in buttonRelease
   275         if (mTimer->isActive() && (mLastKey == buttonId)){
   125         if (mTimer->isActive() && (mLastKey == buttonId)){
   276             mShiftKeyDoubleTap = true;
   126             mShiftKeyDoubleTap = true;
   277         }
   127         }
   307         chopQMarkAndUpdateEditor();
   157         chopQMarkAndUpdateEditor();
   308         mInputMethod->switchMode(buttonId);
   158         mInputMethod->switchMode(buttonId);
   309         return true;
   159         return true;
   310     } 
   160     } 
   311     /* Behavior of Short Press of Asterisk Key when in inline editing state 
   161     /* Behavior of Short Press of Asterisk Key when in inline editing state 
   312 		- Should launch Candidate List if we can continue with prediction i.e. "?" is not displayed
   162         - Should launch Candidate List if we can continue with prediction i.e. "?" is not displayed
   313 		- Should launch Spell Query Dialog if we cannot continue with prediction 
   163         - Should launch Spell Query Dialog if we cannot continue with prediction 
   314 	- Behavior of Short Press of Asterisk Key when not in inline editing state 
   164     - Behavior of Short Press of Asterisk Key when not in inline editing state 
   315 		- Should launch SCT
   165         - Should launch SCT
   316 	*/
   166     */
   317     else if (buttonId == HbInputButton::ButtonKeyCodeAsterisk ) {
   167     else if (buttonId == HbInputButton::ButtonKeyCodeAsterisk ) {
   318 		if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {			
   168         if(!mCanContinuePrediction && (*mCandidates)[mBestGuessLocation].endsWith('?')) {			
   319             //Remove the "?" mark
   169             //Remove the "?" mark
   320             (*mCandidates)[mBestGuessLocation].chop(1);
   170             (*mCandidates)[mBestGuessLocation].chop(1);
   321             updateEditor();
   171             updateEditor();
   322             q->processCustomWord((*mCandidates)[mBestGuessLocation]);
   172             q->launchSpellQueryDialog();
   323             mCanContinuePrediction = true;
   173             mCanContinuePrediction = true;
   324 		}
   174         } else {
   325 		else
   175             mInputMethod->starKeySelected();
   326 			mInputMethod->starKeySelected();
   176         }
   327         return true;
   177         return true;
   328     }	
   178     }
   329     else if (buttonId == HbInputButton::ButtonKeyCodeEnter) {
   179     else if (buttonId == HbInputButton::ButtonKeyCodeEnter) {
   330         mInputMethod->closeKeypad();
   180         mInputMethod->closeKeypad();
   331         return true;
   181         return true;
   332     }
   182     }
   333     if (buttonId == HbInputButton::ButtonKeyCodeShift) {
   183     if (buttonId == HbInputButton::ButtonKeyCodeShift) {
   334         // single tap of shift key toggles prediction status in case insensitive languages
   184         // single tap of shift key toggles prediction status in case insensitive languages
   335         if (!HbInputSettingProxy::instance()->globalInputLanguage().isCaseSensitiveLanguage()) {
   185         if (!HbInputSettingProxy::instance()->globalInputLanguage().isCaseSensitiveLanguage()) {
   336             HbInputSettingProxy::instance()->togglePrediction();
   186             HbInputSettingProxy::instance()->togglePrediction();
   337         } else {
   187         } else {
   338             if (mShiftKeyDoubleTap) {
   188             if (mShiftKeyDoubleTap) {
   339                 mTimer->stop(); 
   189                 mTimer->stop();
   340                 mShiftKeyDoubleTap = false;	
   190                 mShiftKeyDoubleTap = false;
   341                 //mShowTail = false;      
   191                 //mShowTail = false;
   342                 if (HbInputSettingProxy::instance()->globalInputLanguage()== mInputMethod->inputState().language()) {
   192                 if (HbInputSettingProxy::instance()->globalInputLanguage()== mInputMethod->inputState().language()) {
   343                     // in latin variants , double tap of shift key toggles the prediction status	
   193                     // in latin variants , double tap of shift key toggles the prediction status	
   344                     // revert back to the old case as this is a double tap 
   194                     // revert back to the old case as this is a double tap 
   345                     // (the case was changed on the single tap)
   195                     // (the case was changed on the single tap)
   346                     updateTextCase();				 
   196                     updateTextCase();
   347                     q->togglePrediction();
   197                     q->togglePrediction();
   348                 } else {
   198                 } else {
   349                     // if the global language is different from the input mode language, we should 
   199                     // if the global language is different from the input mode language, we should 
   350                     // go back to the root state
   200                     // go back to the root state
   351                     // e.g. double tap of hash/shift key is used to change 
   201                     // e.g. double tap of hash/shift key is used to change 
   352                     // to chinese input mode from latin input mode
   202                     // to chinese input mode from latin input mode
   353                     HbInputState rootState;
   203                     HbInputState rootState;
   354                     mInputMethod->editorRootState(rootState);
   204                     mInputMethod->editorRootState(rootState);
   355                     mInputMethod->activateState(rootState); 		
   205                     mInputMethod->activateState(rootState);
   356                 }
   206                 }
   357             } else {
   207             } else {
   358                 updateTextCase();
   208                 updateTextCase();
   359                 if( !mTimer->isActive()){
   209                 if( !mTimer->isActive()){
   360                     mTimer->start(HbMultiTapTimerTimeout);
   210                     mTimer->start(HbMultiTapTimerTimeout);
   368         mInputMethod->currentKeyboardType() == HbKeyboardSctPortrait) {
   218         mInputMethod->currentKeyboardType() == HbKeyboardSctPortrait) {
   369         q->sctCharacterSelected(QChar(buttonId));
   219         q->sctCharacterSelected(QChar(buttonId));
   370         return true;
   220         return true;
   371     }
   221     }
   372 
   222 
   373     // text input happens on button release		
   223     // text input happens on button release
   374     if (q->HbInputPredictionHandler::filterEvent(keyEvent)) {
   224     if (q->HbInputPredictionHandler::filterEvent(keyEvent)) {
   375         return true;
   225         return true;
   376     }	
   226     }	
   377     return false;
   227     return false;
   378 }
   228 }
   417     //If there was a handling for empty candidate-list, i.e. the engine did not predict
   267     //If there was a handling for empty candidate-list, i.e. the engine did not predict
   418     //any meaningful word for the input sequence.
   268     //any meaningful word for the input sequence.
   419     if(!d->mCanContinuePrediction) {
   269     if(!d->mCanContinuePrediction) {
   420         int eventKey = event->key();
   270         int eventKey = event->key();
   421         switch(eventKey) {
   271         switch(eventKey) {
   422         case Qt::Key_0:        
   272         case Qt::Key_0:
   423         case HbInputButton::ButtonKeyCodeSpace: {
   273         case HbInputButton::ButtonKeyCodeSpace: {
   424             if(d->mCandidates->size() && focusObject) {
   274             if(d->mCandidates->size() && focusObject) {
   425                 //Remove the "?" mark
   275                 //Remove the "?" mark
   426                 (*d->mCandidates)[d->mBestGuessLocation].chop(1);
   276                 (*d->mCandidates)[d->mBestGuessLocation].chop(1);
   427                 d->updateEditor();
   277                 d->updateEditor();
   437             }
   287             }
   438         //For the following set of keys, it does not matter.
   288         //For the following set of keys, it does not matter.
   439         case Qt::Key_Backspace:
   289         case Qt::Key_Backspace:
   440         case HbInputButton::ButtonKeyCodeDelete:
   290         case HbInputButton::ButtonKeyCodeDelete:
   441         case HbInputButton::ButtonKeyCodeEnter:
   291         case HbInputButton::ButtonKeyCodeEnter:
   442 		case HbInputButton::ButtonKeyCodeAsterisk:
   292         case HbInputButton::ButtonKeyCodeAsterisk:
   443         case HbInputButton::ButtonKeyCodeControl:
   293         case HbInputButton::ButtonKeyCodeControl:
   444             break;
   294         case HbInputButton::ButtonKeyCodeSymbol:
   445         /* Behavior for other keys i.e. from key1 to key9 - 
       
   446         To start the long press timer as we need to handle long press functionality i.e Enter corresponding number mapped to a key */
       
   447         case Qt::Key_1:
   295         case Qt::Key_1:
   448         case Qt::Key_2:
   296         case Qt::Key_2:
   449         case Qt::Key_3:
   297         case Qt::Key_3:
   450         case Qt::Key_4:
   298         case Qt::Key_4:
   451         case Qt::Key_5:
   299         case Qt::Key_5:
   452         case Qt::Key_6:
   300         case Qt::Key_6:
   453         case Qt::Key_7:
   301         case Qt::Key_7:
   454         case Qt::Key_8:
   302         case Qt::Key_8:
   455         case Qt::Key_9: {
   303         case Qt::Key_9:
   456             if (event->type() == QEvent::KeyRelease) {
   304             break;
   457                 d->mButtonDown = false;
       
   458             } else {
       
   459                 d->mButtonDown = true;			
       
   460                 d->mLastKey = event->key();		
       
   461             }
       
   462             return true;
       
   463         }
       
   464         //The default behavior for any other key press is just to consume the key event and
   305         //The default behavior for any other key press is just to consume the key event and
   465         //not to do anything.
   306         //not to do anything.
   466         default: {
   307         default: {
   467             return true;
   308             return true;
   468             }
   309             }
   509         case HbInputModeActionFocusRecieved:
   350         case HbInputModeActionFocusRecieved:
   510             HbInputPredictionHandler::actionHandler(HbInputModeActionSetCandidateList);
   351             HbInputPredictionHandler::actionHandler(HbInputModeActionSetCandidateList);
   511             HbInputPredictionHandler::actionHandler(HbInputModeActionSetKeypad);
   352             HbInputPredictionHandler::actionHandler(HbInputModeActionSetKeypad);
   512             d->mTimer->stop();
   353             d->mTimer->stop();
   513             break;
   354             break;
   514 		case HbInputModeActionCloseSpellQuery:
       
   515 			if (d->mInputSpellQuery) {
       
   516 				d->mInputSpellQuery->close();
       
   517 		    }
       
   518 			break;
       
   519         default:
   355         default:
   520             ret = HbInputPredictionHandler::actionHandler(action);
   356             ret = HbInputPredictionHandler::actionHandler(action);
   521             break;
   357             break;
   522     }
   358     }
   523     
   359     
   543 { 
   379 { 
   544     Q_D(const HbInputPrediction12KeyHandler);
   380     Q_D(const HbInputPrediction12KeyHandler);
   545     return d->mEngine != 0;
   381     return d->mEngine != 0;
   546 }
   382 }
   547 
   383 
   548 void HbInputPrediction12KeyHandler::processCustomWord(QString customWord)
       
   549 {
       
   550     Q_D(HbInputPrediction12KeyHandler);
       
   551     if (customWord.size()) {
       
   552 		if(!d->mInputSpellQuery) {
       
   553 			d->mInputSpellQuery = new HbInputSpellQuery(d);
       
   554 		}
       
   555         d->mInputSpellQuery->launch(customWord);
       
   556     }
       
   557     return;	  
       
   558 }
       
   559 //EOF
   384 //EOF