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); |