Merge lp:~sil2100/ubuntu-keyboard/enhance_word_completion into lp:ubuntu-keyboard

Proposed by Łukasz Zemczak
Status: Merged
Approved by: Bill Filler
Approved revision: 168
Merged at revision: 175
Proposed branch: lp:~sil2100/ubuntu-keyboard/enhance_word_completion
Merge into: lp:ubuntu-keyboard
Diff against target: 473 lines (+211/-25)
13 files modified
plugins/pinyin/src/chineselanguagefeatures.cpp (+19/-1)
plugins/pinyin/src/chineselanguagefeatures.h (+1/-0)
plugins/westernsupport/westernlanguagefeatures.cpp (+15/-0)
plugins/westernsupport/westernlanguagefeatures.h (+2/-0)
qml/Keyboard.qml (+1/-0)
qml/KeyboardContainer.qml (+2/-0)
qml/keys/CharKey.qml (+8/-1)
src/lib/logic/abstractlanguagefeatures.h (+2/-0)
src/view/abstracttexteditor.cpp (+94/-16)
src/view/abstracttexteditor.h (+1/-0)
tests/unittests/ut_editor/ut_editor.cpp (+29/-4)
tests/unittests/ut_editor/wordengineprobe.cpp (+32/-0)
tests/unittests/ut_editor/wordengineprobe.h (+5/-3)
To merge this branch: bzr merge lp:~sil2100/ubuntu-keyboard/enhance_word_completion
Reviewer Review Type Date Requested Status
Bill Filler (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Michael Sheldon (community) Needs Fixing
Review via email: mp+214996@code.launchpad.net

Commit message

Changes related to fixing the preedit word completion, enhancing the usage with regards to adding whitespaces, separators. Enhanced autocaps. Added possibility to commit (word-completion) when using separators (., etc). Double-space with auto-correction enabled now results in a full-stop sign. Also, in auto-correct unnecessary whitespaces before separators are removed. Include unit-testing of some of the features.

Description of the change

* Are there any related MPs required for this MP to build/function as expected? Please list.
-> No

* Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)
-> Yes

* Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?
-> Yes, on my mako device

* Did you successfully run all tests found in your component's Test Plan on device or emulator?
-> Yes, on my mako device

* If you changed the UI, was the change specified/approved by design?
-> N/A

* If you changed the packaging (debian), did you subscribe a core-dev to this MP?
-> N/A

Description:

Changes related to fixing the preedit word completion, enhancing the usage with regards to adding whitespaces, separators. Enhanced autocaps.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

One slight issue is the spacing behaviour when using Pinyin. At the moment you have to do a double space to get a space character for Pinyin (and then of course you get two spaces). It behaves correctly when entering characters, in that it's not appending a space after completing a character, but when entering a space on its own (after finishing a character) you currently don't get any output.

153. By Łukasz Zemczak

Enable the double-space as a full stop sequence generator during auto-complete

154. By Łukasz Zemczak

Remove any trailing whitespaces during auto-correct when a separator is inputted and make the double-space action only work in case of space-started auto-correct

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Łukasz Zemczak (sil2100) wrote :

I will look now into the issue with Pinyin - currently it seems to be not working at all even (maliit-server stops due to assertion issues). In the meantime, just a quick comment related to the removal of whitespaces that I made here. The best, cleanest way would be to use preedit for those, but sadly that approach was very very troublesome. Preedit has a specific way of formatting its input. And it also interferes with the word-prediction... Since it was really really troublesome, I decided to use a more 'hacky way' for this - doing backspace actions to remove the whitespaces. It's not perfect, but it seems to be the only sane way without having to modify maliit too much.

155. By Łukasz Zemczak

Fix the new behavior for pinyin

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
156. By Łukasz Zemczak

Add some additional comments

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
157. By Łukasz Zemczak

Add the possibility to commit strings using separators (like dots and commas). Fix pinyin input to consider separators

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
158. By Łukasz Zemczak

Merge trunk

159. By Łukasz Zemczak

Fix the tests, still working on fixing all edge-cases

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
160. By Łukasz Zemczak

Fix all outstanding issues... Refactor the code heavily as it was a 'patch on a patch of a patch'. Now it should be good

161. By Łukasz Zemczak

Merge trunk

162. By Łukasz Zemczak

Add a new unit test for the double-space full-stop

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

I'm finding that when first entering an empty field caps don't get disabled until the second letter has been completed, so "Hello" becomes "HEllo". This seems to be related to the panel.autoCapsTriggered condition on line 114 of the diff, which prevents the keypad state from being set back to NORMAL. With that removed everything appears to work correctly, however I'm not clear on what the intention is there so I might be missing some side effect that I'm unaware of?

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Sadly, this conditional is required to enable activation of autocaps by normal character key-presses. Without this, each character key automatically disables autocaps, making it impossible to triggering it properly. I just need to handle this case better, let me fix this ;)

163. By Łukasz Zemczak

Workaround fix for the broken initial autocaps

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?

 * Yes

Did CI run pass? If not, please explain why.

 * Yes

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?

 * Yes

review: Approve
Revision history for this message
Bill Filler (bfiller) wrote :

Getting close. There are still a few issues that need to be addressed:

For all of these tests, I just open Notes and type a new note

== turn on all the settings (spellcheck, autocomplete, word suggestions)
1) No space is entered after pressing spacebar to commit the word. For example type:
"Hey my"[spacebar]
This should produce
"Hey my " but instead produces "Hey my"
The space does not get added until you type the next word. Whenever spacebar is pressed it should commit the word and add a space.

2) Double tap on spacebar not always adding punctation:
This works correctly if there is a suggested word in the list to complete. i.e
"Hello my fri" [double tap spacebar] produces "Hello my friend. "
But if there is no suggested word, or if word suggestion/auto complete is disabled it does not work.
For example:
"Hello my uubgugugugug"[double tap spacebar] produces "Hello my uubgugugugug " while it should produce "Hello my uubgugugugug.

The rule should be double-tapping spacebar when the preceding character is not a space should always a) commit the word b) add the period + trailing space, regardless if word suggesting existed or not and regardless if word suggestion/auto-complete is enabled. This is how Android and iphone both work

review: Needs Fixing
164. By Łukasz Zemczak

Change the approach: for now let's not use the preedit for appending the whitespaces for auto-correct. Let's actually print it out but remove it when needed. We could do this otherwise, i.e. use preedit and custom formatting strings, but that actually requires more work and is more error prone. Let's do that later. The unit tests need some love still though...

165. By Łukasz Zemczak

Merge trunk

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

As per our earlier discussion, Android doesn't enable double-space = full-stop when auto-complete is disabled. I guess most of the things mentioned should be resolved.

As already mentioned in the trunk commits, now we're doing things differently. No more usage of preedit. It's less clean, but much less error prone. I would consider using preedit again with custom formatting strings, but let's leave that for some later refactoring :)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Spotted one new issue, if you enter a full stop when in a URL/email context (e.g. in the browser address bar or the messaging app email field) a space is now inserted, this behaviour should probably be disabled under these circumstances.

Revision history for this message
Michael Sheldon (michael-sheldon) :
review: Needs Fixing
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

I think we need to be more picky over the punctuation behaviour as well, it currently causes issues when inserting smilies in text. For example, if you try typing "This is getting better :)" you end up with "This is getting better: )"

review: Needs Fixing
Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Ah! Smileys ;) Forgot about those! Let me make a quick fix soon.

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Just a quick heads up - I'm working on this, just have a lot of landing team work nowadays. The fix for those issues is almost done, just need to find 10 free minutes.

166. By Łukasz Zemczak

Do not consider : and ; as separators right now

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
167. By Łukasz Zemczak

Yeah, this should be much easier to do the detection of content type - as all non free text content types explicitly disable preedit.

168. By Łukasz Zemczak

Merge trunk

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Should be ok now ;p! Curse you landing team work!

btw. I tried connecting to the contentType changed signals, but those didn't really work. But this way should cover all the currently known cases as well.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Bill Filler (bfiller) wrote :

I've tested out of silo 3, it's all working nicely. Good job Sil!

Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?
yes

Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/<package-name>) on device or emulator?
yes

Did CI run pass? If not, please explain why.
yes

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?
yes

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/pinyin/src/chineselanguagefeatures.cpp'
--- plugins/pinyin/src/chineselanguagefeatures.cpp 2014-04-15 12:18:47 +0000
+++ plugins/pinyin/src/chineselanguagefeatures.cpp 2014-06-11 13:16:05 +0000
@@ -47,6 +47,24 @@
4747
48QString ChineseLanguageFeatures::appendixForReplacedPreedit(const QString &preedit) const48QString ChineseLanguageFeatures::appendixForReplacedPreedit(const QString &preedit) const
49{49{
50 Q_UNUSED(preedit)50 if (isSeparator(preedit.right(1))) {
51 return QString(" ");
52 }
53
51 return QString("");54 return QString("");
52}55}
56
57bool ChineseLanguageFeatures::isSeparator(const QString &text) const
58{
59 static const QString separators = QString::fromUtf8("。、,!?:;\r\n");
60
61 if (text.isEmpty()) {
62 return false;
63 }
64
65 if (separators.contains(text.right(1))) {
66 return true;
67 }
68
69 return false;
70}
53\ No newline at end of file71\ No newline at end of file
5472
=== modified file 'plugins/pinyin/src/chineselanguagefeatures.h'
--- plugins/pinyin/src/chineselanguagefeatures.h 2014-04-15 12:18:47 +0000
+++ plugins/pinyin/src/chineselanguagefeatures.h 2014-06-11 13:16:05 +0000
@@ -31,6 +31,7 @@
31 virtual bool autoCapsAvailable() const;31 virtual bool autoCapsAvailable() const;
32 virtual bool activateAutoCaps(const QString &preedit) const;32 virtual bool activateAutoCaps(const QString &preedit) const;
33 virtual QString appendixForReplacedPreedit(const QString &preedit) const;33 virtual QString appendixForReplacedPreedit(const QString &preedit) const;
34 virtual bool isSeparator(const QString &text) const;
34};35};
3536
36#endif // CHINESELANGUAGEFEATURES_H37#endif // CHINESELANGUAGEFEATURES_H
3738
=== modified file 'plugins/westernsupport/westernlanguagefeatures.cpp'
--- plugins/westernsupport/westernlanguagefeatures.cpp 2014-04-15 12:18:47 +0000
+++ plugins/westernsupport/westernlanguagefeatures.cpp 2014-06-11 13:16:05 +0000
@@ -74,3 +74,18 @@
7474
75 return QString(" ");75 return QString(" ");
76}76}
77
78bool WesternLanguageFeatures::isSeparator(const QString &text) const
79{
80 static const QString separators = QString::fromUtf8(",.!?\r\n");
81
82 if (text.isEmpty()) {
83 return false;
84 }
85
86 if (separators.contains(text.right(1))) {
87 return true;
88 }
89
90 return false;
91}
7792
=== modified file 'plugins/westernsupport/westernlanguagefeatures.h'
--- plugins/westernsupport/westernlanguagefeatures.h 2014-04-15 12:18:47 +0000
+++ plugins/westernsupport/westernlanguagefeatures.h 2014-06-11 13:16:05 +0000
@@ -46,6 +46,8 @@
46 virtual bool autoCapsAvailable() const;46 virtual bool autoCapsAvailable() const;
47 virtual bool activateAutoCaps(const QString &preedit) const;47 virtual bool activateAutoCaps(const QString &preedit) const;
48 virtual QString appendixForReplacedPreedit(const QString &preedit) const;48 virtual QString appendixForReplacedPreedit(const QString &preedit) const;
49 virtual bool isSeparator(const QString &text) const;
50 virtual QString fullStopSequence() const { return QString("."); }
49};51};
5052
51#endif // MALIITKEYBOARD_LANGUAGEFEATURES_H53#endif // MALIITKEYBOARD_LANGUAGEFEATURES_H
5254
=== modified file 'qml/Keyboard.qml'
--- qml/Keyboard.qml 2014-02-28 18:25:13 +0000
+++ qml/Keyboard.qml 2014-06-11 13:16:05 +0000
@@ -244,6 +244,7 @@
244 onActivateAutocaps: {244 onActivateAutocaps: {
245 keypad.state = "CHARACTERS";245 keypad.state = "CHARACTERS";
246 keypad.activeKeypadState = "SHIFTED";246 keypad.activeKeypadState = "SHIFTED";
247 keypad.autoCapsTriggered = true;
247 }248 }
248 }249 }
249250
250251
=== modified file 'qml/KeyboardContainer.qml'
--- qml/KeyboardContainer.qml 2014-05-12 20:24:36 +0000
+++ qml/KeyboardContainer.qml 2014-06-11 13:16:05 +0000
@@ -28,6 +28,8 @@
28 property int keyWidth: 028 property int keyWidth: 0
29 property int keyHeight: 029 property int keyHeight: 0
3030
31 property bool autoCapsTriggered: false
32
31 property string activeKeypadState: "NORMAL"33 property string activeKeypadState: "NORMAL"
32 property alias popoverEnabled: extendedKeysSelector.enabled34 property alias popoverEnabled: extendedKeysSelector.enabled
3335
3436
=== modified file 'qml/keys/CharKey.qml'
--- qml/keys/CharKey.qml 2014-05-01 16:39:00 +0000
+++ qml/keys/CharKey.qml 2014-06-11 13:16:05 +0000
@@ -142,9 +142,14 @@
142 onReleased: {142 onReleased: {
143 if (!extendedKeysShown) {143 if (!extendedKeysShown) {
144 event_handler.onKeyReleased(valueToSubmit, action);144 event_handler.onKeyReleased(valueToSubmit, action);
145 if (!skipAutoCaps)145
146 if (panel.autoCapsTriggered) {
147 panel.autoCapsTriggered = false;
148 }
149 else if (!skipAutoCaps) {
146 if (panel.activeKeypadState === "SHIFTED" && panel.state === "CHARACTERS")150 if (panel.activeKeypadState === "SHIFTED" && panel.state === "CHARACTERS")
147 panel.activeKeypadState = "NORMAL"151 panel.activeKeypadState = "NORMAL"
152 }
148 }153 }
149 }154 }
150 onPressed: {155 onPressed: {
@@ -154,6 +159,8 @@
154 if (maliit_input_method.useHapticFeedback)159 if (maliit_input_method.useHapticFeedback)
155 pressEffect.start();160 pressEffect.start();
156161
162 // Quick workaround to fix initial autocaps - not beautiful, but works
163 panel.autoCapsTriggered = false;
157 event_handler.onKeyPressed(valueToSubmit, action);164 event_handler.onKeyPressed(valueToSubmit, action);
158 }165 }
159 }166 }
160167
=== modified file 'src/lib/logic/abstractlanguagefeatures.h'
--- src/lib/logic/abstractlanguagefeatures.h 2014-04-15 12:19:05 +0000
+++ src/lib/logic/abstractlanguagefeatures.h 2014-06-11 13:16:05 +0000
@@ -45,6 +45,8 @@
45 virtual bool autoCapsAvailable() const = 0;45 virtual bool autoCapsAvailable() const = 0;
46 virtual bool activateAutoCaps(const QString &preedit) const = 0;46 virtual bool activateAutoCaps(const QString &preedit) const = 0;
47 virtual QString appendixForReplacedPreedit(const QString &preedit) const = 0;47 virtual QString appendixForReplacedPreedit(const QString &preedit) const = 0;
48 virtual bool isSeparator(const QString &text) const { Q_UNUSED(text); return false; }
49 virtual QString fullStopSequence() const { return QString(); }
48};50};
4951
50#endif // MALIIT_KEYBOARD_ABSTRACTLANGUAGEFEATURES_H52#endif // MALIIT_KEYBOARD_ABSTRACTLANGUAGEFEATURES_H
5153
=== modified file 'src/view/abstracttexteditor.cpp'
--- src/view/abstracttexteditor.cpp 2014-05-27 15:37:37 +0000
+++ src/view/abstracttexteditor.cpp 2014-06-11 13:16:05 +0000
@@ -285,6 +285,8 @@
285 bool auto_caps_enabled;285 bool auto_caps_enabled;
286 int ignore_next_cursor_position;286 int ignore_next_cursor_position;
287 QString ignore_next_surrounding_text;287 QString ignore_next_surrounding_text;
288 bool look_for_a_double_space;
289 QString appendix_for_previous_preedit;
288 int backspace_word_acceleration;290 int backspace_word_acceleration;
289291
290 explicit AbstractTextEditorPrivate(const EditorOptions &new_options,292 explicit AbstractTextEditorPrivate(const EditorOptions &new_options,
@@ -307,6 +309,8 @@
307 , auto_caps_enabled(false)309 , auto_caps_enabled(false)
308 , ignore_next_cursor_position(-1)310 , ignore_next_cursor_position(-1)
309 , ignore_next_surrounding_text()311 , ignore_next_surrounding_text()
312 , look_for_a_double_space(false)
313 , appendix_for_previous_preedit()
310 , backspace_word_acceleration(0)314 , backspace_word_acceleration(0)
311{315{
312 auto_repeat_backspace_timer.setSingleShot(true);316 auto_repeat_backspace_timer.setSingleShot(true);
@@ -415,23 +419,66 @@
415 const QString text = key.label();419 const QString text = key.label();
416 QString keyText = QString("");420 QString keyText = QString("");
417 Qt::Key event_key = Qt::Key_unknown;421 Qt::Key event_key = Qt::Key_unknown;
422 bool look_for_a_double_space = d->look_for_a_double_space;
423
424 if (look_for_a_double_space) {
425 // we reset the flag here so that we won't have to add boilerplate code later
426 d->look_for_a_double_space = false;
427 }
418428
419 switch(key.action()) {429 switch(key.action()) {
420 case Key::ActionInsert: {430 case Key::ActionInsert: {
421 d->text->appendToPreedit(text);431 bool alreadyAppended = false;
432 bool auto_caps_activated = false;
433 const bool isSeparator = d->word_engine->languageFeature()->isSeparator(text);
434 const bool replace_preedit = d->auto_correct_enabled && not d->text->primaryCandidate().isEmpty() &&
435 not d->text->preedit().isEmpty() && isSeparator;
422436
423 // computeCandidates can change preedit face, so needs to happen
424 // before sending preedit:
425 if (d->preedit_enabled) {437 if (d->preedit_enabled) {
426 d->word_engine->computeCandidates(d->text.data());438 if (replace_preedit) {
427 }439 // this means we should commit the candidate, add the separator and whitespace
428440 d->text->setPreedit(d->text->primaryCandidate());
429 sendPreeditString(d->text->preedit(), d->text->preeditFace(),441 d->text->appendToPreedit(text);
430 Replacement(d->text->cursorPosition()));442 d->appendix_for_previous_preedit = d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit());
443 d->text->appendToPreedit(d->appendix_for_previous_preedit);
444 commitPreedit();
445 auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(d->text->surroundingLeft() + d->text->preedit() + text);
446 alreadyAppended = true;
447 }
448 else if (d->auto_correct_enabled && isSeparator) {
449 // remove all whitespaces before the separator, then add a whitespace after it
450 removeTrailingWhitespaces();
451
452 d->text->appendToPreedit(text);
453 auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(d->text->surroundingLeft() + d->text->preedit());
454 d->text->appendToPreedit(d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit()));
455 commitPreedit();
456 alreadyAppended = true;
457 }
458 }
459
460 // if we had modified the preedit already because of a separator entry, there is no need to perform all the
461 // steps like appending the input or computing candidates - as all we needed was already done in the previous part
462 if (not alreadyAppended) {
463 d->text->appendToPreedit(text);
464
465 // computeCandidates can change preedit face, so needs to happen
466 // before sending preedit:
467 if (d->preedit_enabled) {
468 d->word_engine->computeCandidates(d->text.data());
469 }
470
471 sendPreeditString(d->text->preedit(), d->text->preeditFace(),
472 Replacement(d->text->cursorPosition()));
473 }
431474
432 if (not d->preedit_enabled) {475 if (not d->preedit_enabled) {
433 commitPreedit();476 commitPreedit();
434 }477 }
478 else if (auto_caps_activated && d->auto_caps_enabled) {
479 // standard input (like certain separators, e.g. '.' in western languages) can also trigger autoCaps
480 Q_EMIT autoCapsActivated();
481 }
435 } break;482 } break;
436483
437 case Key::ActionBackspace: {484 case Key::ActionBackspace: {
@@ -445,17 +492,31 @@
445 } break;492 } break;
446493
447 case Key::ActionSpace: {494 case Key::ActionSpace: {
495 QString space = " ";
448 QString textOnLeft = d->text->surroundingLeft() + d->text->preedit();496 QString textOnLeft = d->text->surroundingLeft() + d->text->preedit();
449 const bool auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(textOnLeft);497 bool auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(textOnLeft);
450 const bool replace_preedit = d->auto_correct_enabled && not d->text->primaryCandidate().isEmpty() && not d->text->preedit().isEmpty();498 const bool replace_preedit = d->auto_correct_enabled && not d->text->primaryCandidate().isEmpty() && not d->text->preedit().isEmpty();
499 const QString stopSequence = d->word_engine->languageFeature()->fullStopSequence();
500
501 // every double-space character inputs one-after-another force a full-stop, so trigger it if needed
502 if (d->preedit_enabled && d->auto_correct_enabled && not look_for_a_double_space) {
503 d->look_for_a_double_space = true;
504 }
451505
452 if (replace_preedit) {506 if (replace_preedit) {
453 const QString &appendix = d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit());507 space = d->appendix_for_previous_preedit = d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit());
454 d->text->setPreedit(d->text->primaryCandidate());508 d->text->setPreedit(d->text->primaryCandidate());
455 d->text->appendToPreedit(appendix);509 }
456 } else {510 else if (look_for_a_double_space && not stopSequence.isEmpty()) {
457 d->text->appendToPreedit(" ");511 removeTrailingWhitespaces();
458 }512 d->text->appendToPreedit(d->word_engine->languageFeature()->fullStopSequence());
513
514 // we need to re-evaluate autocaps after our changes to the preedit
515 textOnLeft = d->text->surroundingLeft() + d->text->preedit();
516 auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(textOnLeft);
517 }
518
519 d->text->appendToPreedit(space);
459 commitPreedit();520 commitPreedit();
460521
461 if (auto_caps_activated && d->auto_caps_enabled) {522 if (auto_caps_activated && d->auto_caps_enabled) {
@@ -578,8 +639,10 @@
578639
579 d->text->setPreedit(replacement);640 d->text->setPreedit(replacement);
580 const bool auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(d->text->preedit());641 const bool auto_caps_activated = d->word_engine->languageFeature()->activateAutoCaps(d->text->preedit());
581 const QString appendix = d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit());642 d->appendix_for_previous_preedit = d->word_engine->languageFeature()->appendixForReplacedPreedit(d->text->preedit());
582 d->text->appendToPreedit(appendix);643 if (d->auto_correct_enabled) {
644 d->text->appendToPreedit(d->appendix_for_previous_preedit);
645 }
583 commitPreedit();646 commitPreedit();
584647
585 if (auto_caps_activated && d->auto_caps_enabled) {648 if (auto_caps_activated && d->auto_caps_enabled) {
@@ -674,6 +737,21 @@
674 d->word_engine->clearCandidates();737 d->word_engine->clearCandidates();
675}738}
676739
740void AbstractTextEditor::removeTrailingWhitespaces()
741{
742 Q_D(AbstractTextEditor);
743
744 const QString textOnLeft = d->text->surroundingLeft() + d->text->preedit();
745
746 QString::const_iterator begin = textOnLeft.cbegin();
747 QString::const_iterator i = textOnLeft.cend();
748 while (i != begin) {
749 --i;
750 if (*i != ' ') break;
751 singleBackspace();
752 }
753}
754
677// TODO: this implementation does not take into account following features:755// TODO: this implementation does not take into account following features:
678// 1) preedit string756// 1) preedit string
679// if there is preedit then first call to autoRepeatBackspace should clean it completely757// if there is preedit then first call to autoRepeatBackspace should clean it completely
680758
=== modified file 'src/view/abstracttexteditor.h'
--- src/view/abstracttexteditor.h 2014-05-14 13:14:34 +0000
+++ src/view/abstracttexteditor.h 2014-06-11 13:16:05 +0000
@@ -158,6 +158,7 @@
158 virtual void singleBackspace();158 virtual void singleBackspace();
159159
160 void commitPreedit();160 void commitPreedit();
161 void removeTrailingWhitespaces();
161 Q_SLOT void autoRepeatBackspace();162 Q_SLOT void autoRepeatBackspace();
162 void autoRepeatWordBackspace();163 void autoRepeatWordBackspace();
163 QString wordLeftOfCursor() const;164 QString wordLeftOfCursor() const;
164165
=== modified file 'tests/unittests/ut_editor/ut_editor.cpp'
--- tests/unittests/ut_editor/ut_editor.cpp 2013-12-19 15:55:17 +0000
+++ tests/unittests/ut_editor/ut_editor.cpp 2014-06-11 13:16:05 +0000
@@ -69,6 +69,8 @@
69 Key key;69 Key key;
70 if (c.isSpace()) {70 if (c.isSpace()) {
71 key.setAction(Key::ActionSpace);71 key.setAction(Key::ActionSpace);
72 } else if (c == '\r') {
73 key.setAction(Key::ActionReturn);
72 } else {74 } else {
73 key.setAction(Key::ActionInsert);75 key.setAction(Key::ActionInsert);
74 key.rLabel() = QString(c);76 key.rLabel() = QString(c);
@@ -101,12 +103,24 @@
101 << false << "Helol Wordl! " << "Helol Wordl! ";103 << false << "Helol Wordl! " << "Helol Wordl! ";
102 QTest::newRow("auto-correct disabled, multiple punctation")104 QTest::newRow("auto-correct disabled, multiple punctation")
103 << false << "Helol Wordl!! " << "Helol Wordl!! ";105 << false << "Helol Wordl!! " << "Helol Wordl!! ";
104 QTest::newRow("auto-correct enabled, digits")106 QTest::newRow("auto-correct disabled, digits")
105 << false << "Helol Wordl12 " << "Helol Wordl12 ";107 << false << "Helol Wordl12 " << "Helol Wordl12 ";
106// QTest::newRow("auto-correct enabled")108// QTest::newRow("auto-correct enabled")
107// << true << "Helol Wordl! " << "Hello World! ";109// << true << "Helol Wordl! " << "Hello World! ";
108// QTest::newRow("auto-correct enabled, multiple punctation")110// QTest::newRow("auto-correct enabled, multiple punctation")
109// << true << "Helol Wordl!! " << "Hello World!! ";111// << true << "Helol Wordl!! " << "Hello World!! ";
112
113 // Tests for the auto-correct and separator-at-end behavior
114 // FIXME: In the current testing infra, we cannot really test this properly, as we are using the 'backspace' character
115 // a lot during auto-correction, which is currently not handled too well here.
116 QTest::newRow("auto-correct enabled, commit with space, check separators")
117 << true << "Hel ,Wor ." << "Hello , World . ";
118 QTest::newRow("auto-correct enabled, commit with separators, check separators")
119 << true << "Hel.Wor." << "Hello. World. ";
120 QTest::newRow("auto-correct enabled, check if two spaces are full-stop")
121 << true << "Hel " << "Hello . ";
122 //QTest::newRow("auto-correct enabled, check removal of unnecessary whitespaces")
123 // << true << "Hello. . " << "Hello.. ";
110 }124 }
111125
112 Q_SLOT void testAutoCorrect()126 Q_SLOT void testAutoCorrect()
@@ -169,14 +183,24 @@
169 << false << "This is a \"first sentence\". And a second, one! "183 << false << "This is a \"first sentence\". And a second, one! "
170 << "This is a \"first sentence\". And a second, one! " << 2;184 << "This is a \"first sentence\". And a second, one! " << 2;
171 QTest::newRow("auto-correct enabled, multiple sentences with mixed punctation")185 QTest::newRow("auto-correct enabled, multiple sentences with mixed punctation")
172 << true << "This is a \"first sentence\". And a second, one! "186 << true << "This is a \"first sentence\".And a second,one!"
173 << "This is a \"first sentence\". And a second, one! " << 2;187 << "This is a \"first sentence\". And a second, one! " << 2;
174 QTest::newRow("auto-correct disabled, multiple sentences with dots")188 QTest::newRow("auto-correct disabled, multiple sentences with dots")
175 << false << "First sentence. Second one. And Third. "189 << false << "First sentence. Second one. And Third. "
176 << "First sentence. Second one. And Third. " << 3;190 << "First sentence. Second one. And Third. " << 3;
177 QTest::newRow("auto-correct enabled, multiple sentences with dots")191 QTest::newRow("auto-correct enabled, multiple sentences with dots")
178 << true << "First sentence. Second one. And Third. "192 << true << "First sentence.Second one.And Third."
179 << "First sentence. Second one. And Third. " << 3;193 << "First sentence. Second one. And Third. " << 3;
194
195 // Tests for the auto-correct and autocaps separator functionality
196 // FIXME: In the current testing infra, we cannot really test this properly, as we are using the 'backspace' character
197 // a lot during auto-correction, which is currently not handled too well here.
198 QTest::newRow("auto-correct enabled, autocaps after separator auto-correction")
199 << true << "Hello Wor .This should be autocapsed "
200 << "Hello World . This should be autocapsed " << 1;
201 QTest::newRow("auto-correct enabled, autocaps after separator auto-correction #2")
202 << true << "Hello Wor .This should be autocapsed "
203 << "Hello World . This should be autocapsed " << 1;
180 }204 }
181205
182 Q_SLOT void testAutoCaps()206 Q_SLOT void testAutoCaps()
@@ -196,6 +220,7 @@
196 initializeWordEngine(word_engine);220 initializeWordEngine(word_engine);
197221
198 editor.wordEngine()->setWordPredictionEnabled(true);222 editor.wordEngine()->setWordPredictionEnabled(true);
223 editor.wordEngine()->setEnabled(true);
199 editor.setAutoCorrectEnabled(enable_auto_correct);224 editor.setAutoCorrectEnabled(enable_auto_correct);
200 editor.setPreeditEnabled(true);225 editor.setPreeditEnabled(true);
201 editor.setAutoCapsEnabled(true);226 editor.setAutoCapsEnabled(true);
@@ -204,7 +229,7 @@
204229
205 QCOMPARE(host.commitStringHistory(), expected_commit_history);230 QCOMPARE(host.commitStringHistory(), expected_commit_history);
206 Q_UNUSED(expected_auto_caps_activated_count)231 Q_UNUSED(expected_auto_caps_activated_count)
207// QCOMPARE(auto_caps_activated_spy.count(), expected_auto_caps_activated_count);232 QCOMPARE(auto_caps_activated_spy.count(), expected_auto_caps_activated_count);
208 }233 }
209};234};
210235
211236
=== modified file 'tests/unittests/ut_editor/wordengineprobe.cpp'
--- tests/unittests/ut_editor/wordengineprobe.cpp 2014-04-24 13:18:54 +0000
+++ tests/unittests/ut_editor/wordengineprobe.cpp 2014-06-11 13:16:05 +0000
@@ -31,6 +31,38 @@
3131
32#include "wordengineprobe.h"32#include "wordengineprobe.h"
3333
34// To properly mock language features, we need to realistically determine separators and autoCaps
35// Since unittests use latin letters, we simply use the same methods as in WesternLanguageFeatures
36bool MockLanguageFeatures::activateAutoCaps(const QString &preedit) const
37{
38 static const QString sentenceBreak = QString::fromUtf8("!.?:\r\n");
39
40 if (preedit.isEmpty()) {
41 return false;
42 }
43
44 if (sentenceBreak.contains(preedit.right(1))) {
45 return true;
46 }
47
48 return false;
49}
50
51bool MockLanguageFeatures::isSeparator(const QString &text) const
52{
53 static const QString separators = QString::fromUtf8(",.!?:;\r\n");
54
55 if (text.isEmpty()) {
56 return false;
57 }
58
59 if (separators.contains(text.right(1))) {
60 return true;
61 }
62
63 return false;
64}
65
34namespace MaliitKeyboard {66namespace MaliitKeyboard {
35namespace Logic {67namespace Logic {
3668
3769
=== modified file 'tests/unittests/ut_editor/wordengineprobe.h'
--- tests/unittests/ut_editor/wordengineprobe.h 2014-04-24 13:18:54 +0000
+++ tests/unittests/ut_editor/wordengineprobe.h 2014-06-11 13:16:05 +0000
@@ -43,10 +43,12 @@
43 explicit MockLanguageFeatures() {}43 explicit MockLanguageFeatures() {}
44 virtual ~MockLanguageFeatures() {}44 virtual ~MockLanguageFeatures() {}
4545
46 virtual bool isSeparator(const QString &text) const;
46 virtual bool alwaysShowSuggestions() const { return false; }47 virtual bool alwaysShowSuggestions() const { return false; }
47 virtual bool autoCapsAvailable() const { return false; }48 virtual bool autoCapsAvailable() const { return true; }
48 virtual bool activateAutoCaps(const QString &preedit) const { Q_UNUSED(preedit); return false; }49 virtual bool activateAutoCaps(const QString &preedit) const;
49 virtual QString appendixForReplacedPreedit(const QString &preedit) const { Q_UNUSED(preedit); return ""; }50 virtual QString appendixForReplacedPreedit(const QString &preedit) const { Q_UNUSED(preedit); return " "; }
51 virtual QString fullStopSequence() const { return QString("."); }
50};52};
5153
52namespace MaliitKeyboard {54namespace MaliitKeyboard {

Subscribers

People subscribed via source and target branches