Merge lp:~cosmos-door/ubuntu-keyboard/japanese-keyboard-rebooted into lp:ubuntu-keyboard

Proposed by Mitsuya Shibata
Status: Merged
Approved by: Michael Sheldon
Approved revision: 418
Merged at revision: 447
Proposed branch: lp:~cosmos-door/ubuntu-keyboard/japanese-keyboard-rebooted
Merge into: lp:ubuntu-keyboard
Diff against target: 2321 lines (+1925/-4)
38 files modified
debian/control (+11/-0)
debian/server.conf (+1/-0)
debian/ubuntu-keyboard-japanese.install (+1/-0)
plugins/ja/ja.pro (+9/-0)
plugins/ja/qml/Keyboard_ja.qml (+118/-0)
plugins/ja/qml/Keyboard_ja_email.qml (+121/-0)
plugins/ja/qml/Keyboard_ja_url.qml (+121/-0)
plugins/ja/qml/Keyboard_ja_url_search.qml (+121/-0)
plugins/ja/qml/keys/CommitKey.qml (+40/-0)
plugins/ja/qml/keys/CursorKey.qml (+58/-0)
plugins/ja/qml/keys/DomainKey.qml (+42/-0)
plugins/ja/qml/keys/FlickArea.qml (+79/-0)
plugins/ja/qml/keys/FlickCharKey.qml (+178/-0)
plugins/ja/qml/keys/FlickPop.qml (+70/-0)
plugins/ja/qml/keys/FlickPopKey.qml (+42/-0)
plugins/ja/qml/keys/KanaSwitchKey.qml (+85/-0)
plugins/ja/qml/keys/ModifierKey.qml (+79/-0)
plugins/ja/qml/keys/UndoKey.qml (+25/-0)
plugins/ja/qml/keys/key_constants.js (+31/-0)
plugins/ja/qml/keys/modifier.js (+102/-0)
plugins/ja/qml/qml.pro (+31/-0)
plugins/ja/src/anthyadapter.cpp (+117/-0)
plugins/ja/src/anthyadapter.h (+45/-0)
plugins/ja/src/japaneselanguagefeatures.cpp (+92/-0)
plugins/ja/src/japaneselanguagefeatures.h (+42/-0)
plugins/ja/src/japaneseplugin.cpp (+59/-0)
plugins/ja/src/japaneseplugin.h (+43/-0)
plugins/ja/src/japaneseplugin.json (+7/-0)
plugins/ja/src/src.pro (+39/-0)
plugins/plugins.pro (+1/-0)
qml/keys/languages.js (+1/-0)
src/lib/logic/abstractlanguagefeatures.h (+2/-0)
src/lib/logic/eventhandler.cpp (+2/-0)
src/plugin/inputmethod.cpp (+29/-0)
src/plugin/inputmethod.h (+9/-0)
src/plugin/inputmethod_p.h (+3/-0)
src/view/abstracttexteditor.cpp (+65/-4)
src/view/abstracttexteditor.h (+4/-0)
To merge this branch: bzr merge lp:~cosmos-door/ubuntu-keyboard/japanese-keyboard-rebooted
Reviewer Review Type Date Requested Status
Michael Sheldon (community) Approve
Mitsuya Shibata (community) Needs Resubmitting
Ken VanDine packaging Approve
Review via email: mp+268158@code.launchpad.net

Commit message

Implement Japanese keyboard layout

Description of the change

This is rewrite code to input Japanese from ubuntu-keyboard.

How to try it:

1. install ubuntu-keyboard this branch

2. setup japanese environment and enable japanese input method
    1. launch System Settings and select Language & Text
    2. set "Display language" to "日本語(日本)" (most bottom in list)
    3. set "Keyboard layouts" to "[Ja] 日本語"

3. return to home scope and tap search icon

4. enjoy japanese input!
    - Japanese input method use "Flick input" which is commonly used japanese
      smartphones.
    - please refer following video about how to input.
      http://www.youtube.com/watch?v=pbGdEeHzFnk

Note about this branch:

1. support single kana-kanji conversion only
    - does not support resize segment.

2. publish preedit and cursor_position property to QML
    - Japanese input method use preedit hardly.
    - So needs to edit preedit from QML before commit it.
    - This branch add properties preedit and cursor_position to maliit_input_method.
    - And emit signal by changed this property from abstracttexteditor.
      src/plugin/inputmethod.{h,cpp}
      src/plugin/inputmethod_p.h
      src/view/abstracttexteditor.cpp
      src/view/abstracttexteditor.{h,cpp}
      src/lib/logic/eventhandler.cpp

Thanks!

To post a comment you must log in.
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Hi Mitsuya,

 Thanks for updating this, I've only just started reviewing it so there'll be some more comments to come later, but the most immediate issue with this branch is that it doesn't install the japanese plugin's "keys" directory (plugins/ja/qml/keys).

 I've also made a couple of inline comments at locations where it's still using the old relative path imports for the global keys directory, this should now be done as "import keys 1.0" as this we allow the plugin to be installed separately from the rest of maliit in the future (e.g. as part of a custom tarball, or possibly as a click package at some point)

Thanks!

review: Needs Fixing
404. By Mitsuya Shibata

Install customized qml files for Japanese layout.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

> Thanks for updating this, I've only just started reviewing it so there'll be
> some more comments to come later, but the most immediate issue with this
> branch is that it doesn't install the japanese plugin's "keys" directory
> (plugins/ja/qml/keys).

oh, sorry... I fixed qml.pro, it will install plugins/ja/qml/keys too.

> I've also made a couple of inline comments at locations where it's still
> using the old relative path imports for the global keys directory, this should
> now be done as "import keys 1.0" as this we allow the plugin to be installed
> separately from the rest of maliit in the future (e.g. as part of a custom
> tarball, or possibly as a click package at some point)

Changed to "import keys 1.0".

Thank you for your review!

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

Looking really good, just a few small things needing fixing:

1) The cursor keys move two characters at a time (it looks like they're moving the cursor on both the press and release events)

2) In the character selection pop-over the characters that aren't currently selected should use the same colour as the selection pop-over on the other keyboard layouts (this is done by setting the opacity to 0.6 when not selected)

3) If touch feedback is enabled in settings then sliding between characters on the selection pop-over should trigger haptic feedback via pressEffect.start() (same as on other keyboard layouts)

4) The copyright year on a lot of the added files is listed as 2012/2013/2014, this should be 2015 since these are new files

5) Is it correct that the URL and email layouts should be a non-Japanese qwerty layout? (If so it might be worth populating the URL key with useful Japanese TLDs like .jp, .co.jp, etc.)

6) Could you add a comment to the modifier.js explaining the purpose of the map and normalize arrays?

review: Needs Fixing
405. By Mitsuya Shibata

fixes copyright year and add some comments

406. By Mitsuya Shibata

fixes double key released for cursor keys

407. By Mitsuya Shibata

set the text opacity to 0.6 when not selected in the selection pop-over

408. By Mitsuya Shibata

trigger haptic feedback on the selection pop-over too.

409. By Mitsuya Shibata

add email/url layout for japanese.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Thank you for more reviewing!

I fixed all of your pointed out. Please check it.

> 1) The cursor keys move two characters at a time (it looks like they're moving
> the cursor on both the press and release events)

Fixed typo (s/Released/Pressed/)

> 2) In the character selection pop-over the characters that aren't currently
> selected should use the same colour as the selection pop-over on the other
> keyboard layouts (this is done by setting the opacity to 0.6 when not
> selected)

Set opacity for unselected Text element.

> 3) If touch feedback is enabled in settings then sliding between characters on
> the selection pop-over should trigger haptic feedback via pressEffect.start()
> (same as on other keyboard layouts)

Add haptic feedback and not audio feedback (same as original extended key).

> 4) The copyright year on a lot of the added files is listed as 2012/2013/2014,
> this should be 2015 since these are new files

Set all 2015.

> 5) Is it correct that the URL and email layouts should be a non-Japanese
> qwerty layout? (If so it might be worth populating the URL key with useful
> Japanese TLDs like .jp, .co.jp, etc.)

Change email/url layout to same as normal Japanese layout.
Commonly used Japanese TLD is ".com" and ".jp".
Indeed ".co.jp" is used too, but doesn't manual typewith frequently as url/email .

Additionally to this, set email/url default layout alphabet instead of kana.

> 6) Could you add a comment to the modifier.js explaining the purpose of the
> map and normalize arrays?

Add comment.

Thanks!

review: Needs Resubmitting
Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

Is there any chance to be merged for OTA-8 or OTA-9?

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

Hi Mitsuya,

 Sorry for the delay in replying, I hadn't spotted your updates; I'll try to get it re-reviewed and included for OTA-9

Cheers,
 Mike

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

Hi Mitsuya,

 I've just been re-reviewing this, and it looks great; but I've found one last issue, whereby the cursor keys don't work correctly whilst still in pre-edit. I'm wondering if it might be best to simply call Qt.inputMethod.commit() when pressing the cursor keys?

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

It looks like the cursor does get moved internally within maliit (so deletions and insertions occur in the correct place) but the visual cursor doesn't move. I think just committing the text prior to moving the cursor would be the simplest solution for this.

410. By Mitsuya Shibata

Merge upstream's changes

411. By Mitsuya Shibata

Switch to Ubuntu.Components 1.3 and QtQuick 2.4

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

I rebased newer ubuntu-keyboard code.

About cursor key:
I think "commit" is just commit current preedit, then clear preedit and predictions.
In this means, a preedit in Japanese should not be cleared by cursor key,
should be moved just cursor position.

Can I move visible cursor position without commit?

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Perhaps I can use cursor_pos_override argument of setPreedit() in src/lib/models/text.h.

However AbstractTextEditor::replacePreedit() uses text->setPreedit() without 2nd argument.
I will try to customize replacePreedit().

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Umm... cursor_pos_override just updates m_cursor_position...
Anyway, when exists preedit, press twice left and insert any character, then update cursor position.
I hope there are any hint in this behaviour.

412. By Mitsuya Shibata

fix moving cursor position in preedit by cursor key

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

Finally fixed cursor key problem in rev412. Could you review it?

IMPORTANT NOTE:
Revision 412 modify code in singleBackspace() in src/view/abstracttexteditor.cpp.
It will affect other language not only Japanese.
I believe this modification does not change behaviours of backspace.

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

Hi Mitsuya,

 The changes appear to have fixed the cursor issue nicely, and I haven't seen any negative effects on other layouts, so that's looking good, great work :).

 Unfortunately I've found one more issue: if an ideographic space character (second function from the normal space) is inserted and then committed without any other characters, all predictions are broken until the user switches to another layout and back (effectively unloading and then reloading the Japanese word engine).

 One other quick question, is it normal in Japanese input methods for the return key to be used for committing pre-edit strings? For all other layouts this is done by the space key. I'm happy to leave it with the return key if that's what most Japanese users would already expect, but otherwise it would be good to keep consistent with other layouts if possible.

Thanks!
 Mike.

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

Actually after a bit of further testing it doesn't appear to be directly related to the ideographic space, it seems it can happen with any string if you type it quickly and the commit (presumably whilst anthy is still processing predictions?)

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Thank you your review!

> quickly typing problem

I can't reproduce yet. Could you tell me any typing sample word (and any apps)?

> enter key

Yes, Japanese users expect return key as "commit preedit".
Additionally, in desktop, space key means "change next candidate of the preedit".
I think return key label should not be changed.

More generally, Japanese input method change label of return key
to "確定" ("commit" in Japanease) if in preedit.
I would like to implement this feature in the future.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hmm... it seems that plugins/ja/src/anthyadapter.cpp isn't reentrant.
I'll check more deeply. Thanks!

413. By Mitsuya Shibata

fix problem with parsePredictionText signal on parse()

If parsePredictionText signal is issued when AnthyAdapter::parse() in
procedure, new preedit is saved to JapanesePlugin::m_nextWord then return back.

When AnthyAdapter::parse() is finished, JapanesePlugin::finishedProcessing() is
called. And if parsed text is differ from m_nextWord, retry to parse().

This commit fix to pass wrong old word to new parse() call.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Micahel,

I found a problem in plugins/ja/src/japaneseplugin.cpp and fixed it.
Perhaps it will be related you found quickly typing problem.
Could you retry it?

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

Hi Mitsuya,

 That seems to have fixed it, great work! I'm just waiting on some fixes to unity8 that are causing some issues with the autopilot tests and then we can see about getting your branch landed :)

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

Hi Mitsuya,

 I'm afraid during my final run through the test plan for this I spotted another issue, the bottom row of keys isn't positioned correctly in the landscape view, here's a screenshot showing the issue: http://mikeasoft.com/~mike/jp-landscape.png

 Once that's fixed we should be able to land this :)

Cheers,
 Mike.

review: Needs Fixing
Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

OK, I can reproduce it. However layout is changed English layout then back to Japanese layout, bottom row is positioned correctly. Umm...

414. By Mitsuya Shibata

fix layout in landscape mode.

The height of Language key should be keyHeight.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Ah, OK. Language key is wrong height. Fixed.

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

Great, thanks, one last little thing I spotted, the backspace icon is offset slightly, this actually looks like a bug in the leftSide/rightSide handling for action keys, so for now I'd suggest you just set the width of that key to "panel.keyWidth". Then as a separate task I'll fix the action key icon positioning at a later date and also update all the existing layouts to use leftSide/rightSide for shift and backspace (which they don't currently do).

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

One other thing, would it not make more sense for the "." to be the primary key on the URL layout's url key instead of the ","?

Revision history for this message
Ken VanDine (ken-vandine) wrote :

packaging looks good

review: Approve (packaging)
Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

> I'd suggest you just set the width of that key to "panel.keyWidth".

If set width or remove "rightSide", then first row will be right offset.
This is caused by no rightMargin in CharKey.
Should I push the code to remain the layout corruption?

https://goo.gl/photos/bG5ZxHxfyMhExc926

> would it not make more sense for the "." to be the primary key on the URL layout's url key instead of the ","?

Indeed. To operation coherency, I will swap "," and "." at all keyboard.

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

Hi Mitsuya,

 Just did a quick test, you can work around that by setting the width on the UndoKey as well as the width on the BackspaceKey, then everything will align correctly.

Cheers,
 Mike.

415. By Mitsuya Shibata

add workaround for backspace icon misalignment

416. By Mitsuya Shibata

swap "," and "." which is mainly used to input url and email.

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

Thanks you for nice advice!
I pushed codes to fix problems which you pointed out.

Thanks,

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

Great, thanks; I'll run that through the test plan one last time on Monday and then hopefully we can get it landed :)

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

Hey Mitsuya,

 Sorry! Spotted another issue, you must be getting really tired of me saying "one last thing..." ;)

 The commit key isn't inserting the primary candidate (the bold candidate) when in auto-complete mode, instead it inserts the user's input unmodified. Is this deliberate (i.e. does the Japanese keyboard not really support auto-complete at all)? If so then we shouldn't be highlighting a primary candidate for Japanese, otherwise pressing the commit key should input the primary candidate instead of the user input.

review: Needs Fixing
417. By Mitsuya Shibata

set primary candidate to user input string

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Hi Michael,

Indeed. Generally in Japanese, the commit key should insert the preedit string (primary purpose to input Hiragana).
To clarify which candidate will be committed, I set the primary candidate to the preedit string.

Is it okay?

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

Okay, that sounds good; I'll kick off a rebuild now and retest when it's done

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

Unfortunately I found an extra issue, one of the changes made to the core breaks both the email detection and mid-word insertion based disabling of pre-edit for all the other plugins.

const bool enablePreeditAtInsertion = d->word_engine->languageFeature()->wordEngineAvailable();

^ wordEngineAvailable isn't really an appropriate feature to check for this, as that's going to be true for pretty much all plugins. I think you really need to explicitly add a new language feature for this (which could be called enablePreeditAtInsertion), that's true for Japanese but false for all other plugins.

review: Needs Fixing
418. By Mitsuya Shibata

fix calling wrong method

Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Sorry for my numerous failure...

I fixed wordEngineAvailable() bug. Could you check it?

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

That's great thanks, and no are apologies necessary :) This is by far the most advanced keyboard we've had contributed, so it's natural that there be a few issues in the review.

I've completed a full test now and everything looks good, so I'll propose it for landing now :)

Thanks for all your hard work on this!

review: Approve
Revision history for this message
Mitsuya Shibata (cosmos-door) wrote :

Thank you for your review and merge!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-01-12 11:35:18 +0000
3+++ debian/control 2016-02-19 18:07:05 +0000
4@@ -5,6 +5,7 @@
5 XSBC-Original-Maintainer: Michael Hasselmann <michaelh@openismus.com>
6 Build-Depends: debhelper (>= 9),
7 doxygen,
8+ libanthy-dev,
9 libgl1-mesa-dev | libgl-dev,
10 libgles2-mesa-dev,
11 libglib2.0-dev,
12@@ -98,6 +99,7 @@
13 ubuntu-keyboard-hungarian (>= ${source:Version}),
14 ubuntu-keyboard-icelandic (>= ${source:Version}),
15 ubuntu-keyboard-italian (>= ${source:Version}),
16+ ubuntu-keyboard-japanese (>= ${source:Version}),
17 ubuntu-keyboard-norwegian-bokmal (>= ${source:Version}),
18 ubuntu-keyboard-polish (>= ${source:Version}),
19 ubuntu-keyboard-portuguese (>= ${source:Version}),
20@@ -280,6 +282,15 @@
21 Description: Ubuntu on-screen keyboard data files - Italian
22 Data files for the Ubuntu virtual keyboard - Italian
23
24+Package: ubuntu-keyboard-japanese
25+Architecture: any
26+Depends: ubuntu-keyboard (= ${binary:Version}),
27+ anthy,
28+ ${misc:Depends},
29+ ${shlibs:Depends},
30+Description: Ubuntu on-screen keyboard data files - Japanese
31+ Data files for the Ubuntu virtual keyboard - Japanese
32+
33 Package: ubuntu-keyboard-norwegian-bokmal
34 Architecture: any
35 Depends: ubuntu-keyboard (= ${binary:Version}),
36
37=== modified file 'debian/server.conf'
38--- debian/server.conf 2015-05-11 10:53:43 +0000
39+++ debian/server.conf 2016-02-19 18:07:05 +0000
40@@ -10,6 +10,7 @@
41 libubuntu-keyboard-plugin.so:el, \
42 libubuntu-keyboard-plugin.so:es, \
43 libubuntu-keyboard-plugin.so:ca, \
44+libubuntu-keyboard-plugin.so:ja, \
45 libubuntu-keyboard-plugin.so:zh_cn_cangjie, \
46 libubuntu-keyboard-plugin.so:zh_cn_pinyin, \
47 libubuntu-keyboard-plugin.so:zh_cn_zhuyin,
48
49=== added file 'debian/ubuntu-keyboard-japanese.install'
50--- debian/ubuntu-keyboard-japanese.install 1970-01-01 00:00:00 +0000
51+++ debian/ubuntu-keyboard-japanese.install 2016-02-19 18:07:05 +0000
52@@ -0,0 +1,1 @@
53+usr/share/maliit/plugins/com/ubuntu/lib/ja/
54
55=== added directory 'plugins/ja'
56=== added file 'plugins/ja/ja.pro'
57--- plugins/ja/ja.pro 1970-01-01 00:00:00 +0000
58+++ plugins/ja/ja.pro 2016-02-19 18:07:05 +0000
59@@ -0,0 +1,9 @@
60+CONFIG += ordered
61+TEMPLATE = subdirs
62+SUBDIRS = \
63+ src \
64+ qml
65+
66+QMAKE_EXTRA_TARGETS += check
67+check.target = check
68+check.CONFIG = recursive
69
70=== added directory 'plugins/ja/qml'
71=== added file 'plugins/ja/qml/Keyboard_ja.qml'
72--- plugins/ja/qml/Keyboard_ja.qml 1970-01-01 00:00:00 +0000
73+++ plugins/ja/qml/Keyboard_ja.qml 2016-02-19 18:07:05 +0000
74@@ -0,0 +1,118 @@
75+/*
76+ * Copyright 2015 Canonical Ltd.
77+ *
78+ * This program is free software; you can redistribute it and/or modify
79+ * it under the terms of the GNU Lesser General Public License as published by
80+ * the Free Software Foundation; version 3.
81+ *
82+ * This program is distributed in the hope that it will be useful,
83+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85+ * GNU Lesser General Public License for more details.
86+ *
87+ * You should have received a copy of the GNU Lesser General Public License
88+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
89+ */
90+
91+import QtQuick 2.4
92+import "keys/"
93+import keys 1.0
94+
95+KeyPad {
96+ anchors.fill: parent
97+
98+ content: c1
99+
100+ Column {
101+ id: c1
102+ anchors.fill: parent
103+ spacing: 0
104+
105+ Row {
106+ anchors.horizontalCenter: parent.horizontalCenter;
107+ spacing: 0
108+
109+ UndoKey { leftSide: true; width: panel.keyWidth; }
110+ FlickCharKey {
111+ label: layout.state == "kana" ? "あ" : "@ / : _";
112+ leaves: layout.state == "kana" ? ["あ", "い", "う", "え", "お"] : ["@", "/", ":", "_", "1"];
113+ annotation: layout.state == "kana" ? "" : "1";
114+ }
115+ FlickCharKey {
116+ label: layout.state == "kana" ? "か" : "ABC";
117+ leaves: layout.state == "kana" ? ["か", "き", "く", "け", "こ"] : ["a", "b", "c", "#", "2"];
118+ annotation: layout.state == "kana" ? "" : "2#";
119+ }
120+ FlickCharKey {
121+ label: layout.state == "kana" ? "さ" : "DEF";
122+ leaves: layout.state == "kana" ? ["さ", "し", "す", "せ", "そ"] : ["d", "e", "f", "$", "3"];
123+ annotation: layout.state == "kana" ? "" : "3$";
124+ }
125+ BackspaceKey { rightSide: true; width: panel.keyWidth; }
126+ }
127+
128+ Row {
129+ anchors.horizontalCenter: parent.horizontalCenter;
130+ spacing: 0
131+
132+ CursorKey { action: "left"; }
133+ FlickCharKey {
134+ label: layout.state == "kana" ? "た" : "GHI";
135+ leaves: layout.state == "kana" ? ["た", "ち", "つ", "て", "と"] : ["g", "h", "i", "(", "4"];
136+ annotation: layout.state == "kana" ? "" : "4(";
137+ }
138+ FlickCharKey {
139+ label: layout.state == "kana" ? "な" : "JKL";
140+ leaves: layout.state == "kana" ? ["な", "に", "ぬ", "ね", "の"] : ["j", "k", "l", "\"", "5"];
141+ annotation: layout.state == "kana" ? "" : "5\"";
142+ }
143+ FlickCharKey {
144+ label: layout.state == "kana" ? "は" : "MNO";
145+ leaves: layout.state == "kana" ? ["は", "ひ", "ふ", "へ", "ほ"] : ["m", "n", "o", ")", "6"];
146+ annotation: layout.state == "kana" ? "" : "6)";
147+ }
148+ CursorKey { action: "right"; }
149+ }
150+
151+ Row {
152+ anchors.horizontalCenter: parent.horizontalCenter;
153+ spacing: 0
154+
155+ LanguageKey { id: languageMenuButton; height: panel.keyHeight; }
156+ FlickCharKey {
157+ label: layout.state == "kana" ? "ま" : "PQRS"
158+ leaves: layout.state == "kana" ? ["ま", "み", "む", "め", "も"] : ["p", "q", "r", "s", "7"]
159+ annotation: layout.state == "kana" ? "" : "7"
160+ }
161+ FlickCharKey {
162+ label: layout.state == "kana" ? "や" : "TUV"
163+ leaves: layout.state == "kana" ? ["や", "(", "ゆ", ")", "よ"] : ["t", "u", "v", "'", "8"]
164+ annotation: layout.state == "kana" ? "" : "8'"
165+ }
166+ FlickCharKey {
167+ label: layout.state == "kana" ? "ら" : "WXYZ"
168+ leaves: layout.state == "kana" ? ["ら", "り", "る", "れ", "ろ"] : ["w", "x", "y", "z", "9"]
169+ annotation: layout.state == "kana" ? "" : "9"
170+ }
171+ ActionKey { label: "記号"; action: "symbol"; width: panel.keyWidth; }
172+ }
173+
174+ Row {
175+ anchors.horizontalCenter: parent.horizontalCenter;
176+ spacing: 0
177+
178+ KanaSwitchKey { id: layout; }
179+ ModifierKey { layoutState: layout.state; }
180+ FlickCharKey {
181+ label: layout.state == "kana" ? "わ" : "- + *"
182+ leaves: layout.state == "kana" ? ["わ", "を", "ん", "ー"] : ["-", "+", "0", "*"];
183+ annotation: layout.state == "kana" ? "" : "0";
184+ }
185+ FlickCharKey {
186+ label: layout.state == "kana" ? "、。" : ". , ! ?";
187+ leaves: layout.state == "kana" ? ["、", "。", "!", "?"] : [".", ",", "!", "?"];
188+ }
189+ CommitKey { id: enterKey; width: panel.keyWidth; }
190+ }
191+ } // column
192+}
193
194=== added file 'plugins/ja/qml/Keyboard_ja_email.qml'
195--- plugins/ja/qml/Keyboard_ja_email.qml 1970-01-01 00:00:00 +0000
196+++ plugins/ja/qml/Keyboard_ja_email.qml 2016-02-19 18:07:05 +0000
197@@ -0,0 +1,121 @@
198+/*
199+ * Copyright 2015 Canonical Ltd.
200+ *
201+ * This program is free software; you can redistribute it and/or modify
202+ * it under the terms of the GNU Lesser General Public License as published by
203+ * the Free Software Foundation; version 3.
204+ *
205+ * This program is distributed in the hope that it will be useful,
206+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
207+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
208+ * GNU Lesser General Public License for more details.
209+ *
210+ * You should have received a copy of the GNU Lesser General Public License
211+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
212+ */
213+
214+import QtQuick 2.4
215+import "keys/"
216+import keys 1.0
217+
218+KeyPad {
219+ anchors.fill: parent
220+
221+ content: c1
222+
223+ Column {
224+ id: c1
225+ anchors.fill: parent
226+ spacing: 0
227+
228+ Row {
229+ anchors.horizontalCenter: parent.horizontalCenter;
230+ spacing: 0
231+
232+ UndoKey { leftSide: true; width: panel.keyWidth; }
233+ FlickCharKey {
234+ label: layout.state == "kana" ? "あ" : "@ / : _";
235+ leaves: layout.state == "kana" ? ["あ", "い", "う", "え", "お"] : ["@", "/", ":", "_", "1"];
236+ annotation: layout.state == "kana" ? "" : "1";
237+ }
238+ FlickCharKey {
239+ label: layout.state == "kana" ? "か" : "ABC";
240+ leaves: layout.state == "kana" ? ["か", "き", "く", "け", "こ"] : ["a", "b", "c", "#", "2"];
241+ annotation: layout.state == "kana" ? "" : "2#";
242+ }
243+ FlickCharKey {
244+ label: layout.state == "kana" ? "さ" : "DEF";
245+ leaves: layout.state == "kana" ? ["さ", "し", "す", "せ", "そ"] : ["d", "e", "f", "$", "3"];
246+ annotation: layout.state == "kana" ? "" : "3$";
247+ }
248+ BackspaceKey { rightSide: true; width: panel.keyWidth; }
249+ }
250+
251+ Row {
252+ anchors.horizontalCenter: parent.horizontalCenter;
253+ spacing: 0
254+
255+ CursorKey { action: "left"; }
256+ FlickCharKey {
257+ label: layout.state == "kana" ? "た" : "GHI";
258+ leaves: layout.state == "kana" ? ["た", "ち", "つ", "て", "と"] : ["g", "h", "i", "(", "4"];
259+ annotation: layout.state == "kana" ? "" : "4(";
260+ }
261+ FlickCharKey {
262+ label: layout.state == "kana" ? "な" : "JKL";
263+ leaves: layout.state == "kana" ? ["な", "に", "ぬ", "ね", "の"] : ["j", "k", "l", "\"", "5"];
264+ annotation: layout.state == "kana" ? "" : "5\"";
265+ }
266+ FlickCharKey {
267+ label: layout.state == "kana" ? "は" : "MNO";
268+ leaves: layout.state == "kana" ? ["は", "ひ", "ふ", "へ", "ほ"] : ["m", "n", "o", ")", "6"];
269+ annotation: layout.state == "kana" ? "" : "6)";
270+ }
271+ CursorKey { action: "right"; }
272+ }
273+
274+ Row {
275+ anchors.horizontalCenter: parent.horizontalCenter;
276+ spacing: 0
277+
278+ LanguageKey { id: languageMenuButton; height: panel.keyHeight; }
279+ FlickCharKey {
280+ label: layout.state == "kana" ? "ま" : "PQRS"
281+ leaves: layout.state == "kana" ? ["ま", "み", "む", "め", "も"] : ["p", "q", "r", "s", "7"]
282+ annotation: layout.state == "kana" ? "" : "7"
283+ }
284+ FlickCharKey {
285+ label: layout.state == "kana" ? "や" : "TUV"
286+ leaves: layout.state == "kana" ? ["や", "(", "ゆ", ")", "よ"] : ["t", "u", "v", "'", "8"]
287+ annotation: layout.state == "kana" ? "" : "8'"
288+ }
289+ FlickCharKey {
290+ label: layout.state == "kana" ? "ら" : "WXYZ"
291+ leaves: layout.state == "kana" ? ["ら", "り", "る", "れ", "ろ"] : ["w", "x", "y", "z", "9"]
292+ annotation: layout.state == "kana" ? "" : "9"
293+ }
294+ ActionKey { label: "記号"; action: "symbol"; width: panel.keyWidth; }
295+ }
296+
297+ Row {
298+ anchors.horizontalCenter: parent.horizontalCenter;
299+ spacing: 0
300+
301+ KanaSwitchKey { id: layout; default_state: "alnum" }
302+ ModifierKey { layoutState: layout.state; }
303+ FlickCharKey {
304+ label: layout.state == "kana" ? "わ" : "- + *"
305+ leaves: layout.state == "kana" ? ["わ", "を", "ん", "ー"] : ["-", "+", "0", "*"];
306+ annotation: layout.state == "kana" ? "" : "0";
307+ }
308+ DomainKey {
309+ label: layout.state == "kana" ? "、。" : ". ,";
310+ leaves: layout.state == "kana" ? ["、", "。", "!", "?"] :
311+ [".", ",", "<font size=\"1\">.com</font>", "<font size=\"1\">.jp</font>"];
312+ unstyledLeaves: layout.state == "kana" ? ["、", "。", "!", "?"] : [".", ",", ".com", ".jp"];
313+ annotation: layout.state == "kana" ? "" : ".com .jp"
314+ }
315+ CommitKey { id: enterKey; width: panel.keyWidth; }
316+ }
317+ } // column
318+}
319
320=== added file 'plugins/ja/qml/Keyboard_ja_url.qml'
321--- plugins/ja/qml/Keyboard_ja_url.qml 1970-01-01 00:00:00 +0000
322+++ plugins/ja/qml/Keyboard_ja_url.qml 2016-02-19 18:07:05 +0000
323@@ -0,0 +1,121 @@
324+/*
325+ * Copyright 2015 Canonical Ltd.
326+ *
327+ * This program is free software; you can redistribute it and/or modify
328+ * it under the terms of the GNU Lesser General Public License as published by
329+ * the Free Software Foundation; version 3.
330+ *
331+ * This program is distributed in the hope that it will be useful,
332+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
333+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
334+ * GNU Lesser General Public License for more details.
335+ *
336+ * You should have received a copy of the GNU Lesser General Public License
337+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
338+ */
339+
340+import QtQuick 2.4
341+import "keys/"
342+import keys 1.0
343+
344+KeyPad {
345+ anchors.fill: parent
346+
347+ content: c1
348+
349+ Column {
350+ id: c1
351+ anchors.fill: parent
352+ spacing: 0
353+
354+ Row {
355+ anchors.horizontalCenter: parent.horizontalCenter;
356+ spacing: 0
357+
358+ UndoKey { leftSide: true; width: panel.keyWidth; }
359+ FlickCharKey {
360+ label: layout.state == "kana" ? "あ" : "@ / : _";
361+ leaves: layout.state == "kana" ? ["あ", "い", "う", "え", "お"] : ["@", "/", ":", "_", "1"];
362+ annotation: layout.state == "kana" ? "" : "1";
363+ }
364+ FlickCharKey {
365+ label: layout.state == "kana" ? "か" : "ABC";
366+ leaves: layout.state == "kana" ? ["か", "き", "く", "け", "こ"] : ["a", "b", "c", "#", "2"];
367+ annotation: layout.state == "kana" ? "" : "2#";
368+ }
369+ FlickCharKey {
370+ label: layout.state == "kana" ? "さ" : "DEF";
371+ leaves: layout.state == "kana" ? ["さ", "し", "す", "せ", "そ"] : ["d", "e", "f", "$", "3"];
372+ annotation: layout.state == "kana" ? "" : "3$";
373+ }
374+ BackspaceKey { rightSide: true; width: panel.keyWidth; }
375+ }
376+
377+ Row {
378+ anchors.horizontalCenter: parent.horizontalCenter;
379+ spacing: 0
380+
381+ CursorKey { action: "left"; }
382+ FlickCharKey {
383+ label: layout.state == "kana" ? "た" : "GHI";
384+ leaves: layout.state == "kana" ? ["た", "ち", "つ", "て", "と"] : ["g", "h", "i", "(", "4"];
385+ annotation: layout.state == "kana" ? "" : "4(";
386+ }
387+ FlickCharKey {
388+ label: layout.state == "kana" ? "な" : "JKL";
389+ leaves: layout.state == "kana" ? ["な", "に", "ぬ", "ね", "の"] : ["j", "k", "l", "\"", "5"];
390+ annotation: layout.state == "kana" ? "" : "5\"";
391+ }
392+ FlickCharKey {
393+ label: layout.state == "kana" ? "は" : "MNO";
394+ leaves: layout.state == "kana" ? ["は", "ひ", "ふ", "へ", "ほ"] : ["m", "n", "o", ")", "6"];
395+ annotation: layout.state == "kana" ? "" : "6)";
396+ }
397+ CursorKey { action: "right"; }
398+ }
399+
400+ Row {
401+ anchors.horizontalCenter: parent.horizontalCenter;
402+ spacing: 0
403+
404+ LanguageKey { id: languageMenuButton; height: panel.keyHeight; }
405+ FlickCharKey {
406+ label: layout.state == "kana" ? "ま" : "PQRS"
407+ leaves: layout.state == "kana" ? ["ま", "み", "む", "め", "も"] : ["p", "q", "r", "s", "7"]
408+ annotation: layout.state == "kana" ? "" : "7"
409+ }
410+ FlickCharKey {
411+ label: layout.state == "kana" ? "や" : "TUV"
412+ leaves: layout.state == "kana" ? ["や", "(", "ゆ", ")", "よ"] : ["t", "u", "v", "'", "8"]
413+ annotation: layout.state == "kana" ? "" : "8'"
414+ }
415+ FlickCharKey {
416+ label: layout.state == "kana" ? "ら" : "WXYZ"
417+ leaves: layout.state == "kana" ? ["ら", "り", "る", "れ", "ろ"] : ["w", "x", "y", "z", "9"]
418+ annotation: layout.state == "kana" ? "" : "9"
419+ }
420+ ActionKey { label: "記号"; action: "symbol"; width: panel.keyWidth; }
421+ }
422+
423+ Row {
424+ anchors.horizontalCenter: parent.horizontalCenter;
425+ spacing: 0
426+
427+ KanaSwitchKey { id: layout; default_state: "alnum" }
428+ ModifierKey { layoutState: layout.state; }
429+ FlickCharKey {
430+ label: layout.state == "kana" ? "わ" : "- + *"
431+ leaves: layout.state == "kana" ? ["わ", "を", "ん", "ー"] : ["-", "+", "0", "*"];
432+ annotation: layout.state == "kana" ? "" : "0";
433+ }
434+ DomainKey {
435+ label: layout.state == "kana" ? "、。" : ". ,";
436+ leaves: layout.state == "kana" ? ["、", "。", "!", "?"] :
437+ [".", ",", "<font size=\"1\">.com</font>", "<font size=\"1\">.jp</font>"];
438+ unstyledLeaves: layout.state == "kana" ? ["、", "。", "!", "?"] : [".", ",", ".com", ".jp"];
439+ annotation: layout.state == "kana" ? "" : ".com .jp"
440+ }
441+ CommitKey { id: enterKey; width: panel.keyWidth; }
442+ }
443+ } // column
444+}
445
446=== added file 'plugins/ja/qml/Keyboard_ja_url_search.qml'
447--- plugins/ja/qml/Keyboard_ja_url_search.qml 1970-01-01 00:00:00 +0000
448+++ plugins/ja/qml/Keyboard_ja_url_search.qml 2016-02-19 18:07:05 +0000
449@@ -0,0 +1,121 @@
450+/*
451+ * Copyright 2015 Canonical Ltd.
452+ *
453+ * This program is free software; you can redistribute it and/or modify
454+ * it under the terms of the GNU Lesser General Public License as published by
455+ * the Free Software Foundation; version 3.
456+ *
457+ * This program is distributed in the hope that it will be useful,
458+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
459+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
460+ * GNU Lesser General Public License for more details.
461+ *
462+ * You should have received a copy of the GNU Lesser General Public License
463+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
464+ */
465+
466+import QtQuick 2.4
467+import "keys/"
468+import keys 1.0
469+
470+KeyPad {
471+ anchors.fill: parent
472+
473+ content: c1
474+
475+ Column {
476+ id: c1
477+ anchors.fill: parent
478+ spacing: 0
479+
480+ Row {
481+ anchors.horizontalCenter: parent.horizontalCenter;
482+ spacing: 0
483+
484+ UndoKey { leftSide: true; width: panel.keyWidth; }
485+ FlickCharKey {
486+ label: layout.state == "kana" ? "あ" : "@ / : _";
487+ leaves: layout.state == "kana" ? ["あ", "い", "う", "え", "お"] : ["@", "/", ":", "_", "1"];
488+ annotation: layout.state == "kana" ? "" : "1";
489+ }
490+ FlickCharKey {
491+ label: layout.state == "kana" ? "か" : "ABC";
492+ leaves: layout.state == "kana" ? ["か", "き", "く", "け", "こ"] : ["a", "b", "c", "#", "2"];
493+ annotation: layout.state == "kana" ? "" : "2#";
494+ }
495+ FlickCharKey {
496+ label: layout.state == "kana" ? "さ" : "DEF";
497+ leaves: layout.state == "kana" ? ["さ", "し", "す", "せ", "そ"] : ["d", "e", "f", "$", "3"];
498+ annotation: layout.state == "kana" ? "" : "3$";
499+ }
500+ BackspaceKey { rightSide: true; width: panel.keyWidth; }
501+ }
502+
503+ Row {
504+ anchors.horizontalCenter: parent.horizontalCenter;
505+ spacing: 0
506+
507+ CursorKey { action: "left"; }
508+ FlickCharKey {
509+ label: layout.state == "kana" ? "た" : "GHI";
510+ leaves: layout.state == "kana" ? ["た", "ち", "つ", "て", "と"] : ["g", "h", "i", "(", "4"];
511+ annotation: layout.state == "kana" ? "" : "4(";
512+ }
513+ FlickCharKey {
514+ label: layout.state == "kana" ? "な" : "JKL";
515+ leaves: layout.state == "kana" ? ["な", "に", "ぬ", "ね", "の"] : ["j", "k", "l", "\"", "5"];
516+ annotation: layout.state == "kana" ? "" : "5\"";
517+ }
518+ FlickCharKey {
519+ label: layout.state == "kana" ? "は" : "MNO";
520+ leaves: layout.state == "kana" ? ["は", "ひ", "ふ", "へ", "ほ"] : ["m", "n", "o", ")", "6"];
521+ annotation: layout.state == "kana" ? "" : "6)";
522+ }
523+ CursorKey { action: "right"; }
524+ }
525+
526+ Row {
527+ anchors.horizontalCenter: parent.horizontalCenter;
528+ spacing: 0
529+
530+ LanguageKey { id: languageMenuButton; height: panel.keyHeight; }
531+ FlickCharKey {
532+ label: layout.state == "kana" ? "ま" : "PQRS"
533+ leaves: layout.state == "kana" ? ["ま", "み", "む", "め", "も"] : ["p", "q", "r", "s", "7"]
534+ annotation: layout.state == "kana" ? "" : "7"
535+ }
536+ FlickCharKey {
537+ label: layout.state == "kana" ? "や" : "TUV"
538+ leaves: layout.state == "kana" ? ["や", "(", "ゆ", ")", "よ"] : ["t", "u", "v", "'", "8"]
539+ annotation: layout.state == "kana" ? "" : "8'"
540+ }
541+ FlickCharKey {
542+ label: layout.state == "kana" ? "ら" : "WXYZ"
543+ leaves: layout.state == "kana" ? ["ら", "り", "る", "れ", "ろ"] : ["w", "x", "y", "z", "9"]
544+ annotation: layout.state == "kana" ? "" : "9"
545+ }
546+ ActionKey { label: "記号"; action: "symbol"; width: panel.keyWidth; }
547+ }
548+
549+ Row {
550+ anchors.horizontalCenter: parent.horizontalCenter;
551+ spacing: 0
552+
553+ KanaSwitchKey { id: layout; default_state: "alnum" }
554+ ModifierKey { layoutState: layout.state; }
555+ FlickCharKey {
556+ label: layout.state == "kana" ? "わ" : "- + *"
557+ leaves: layout.state == "kana" ? ["わ", "を", "ん", "ー"] : ["-", "+", "0", "*"];
558+ annotation: layout.state == "kana" ? "" : "0";
559+ }
560+ DomainKey {
561+ label: layout.state == "kana" ? "、。" : ". ,";
562+ leaves: layout.state == "kana" ? ["、", "。", "!", "?"] :
563+ [".", ",", "<font size=\"1\">.com</font>", "<font size=\"1\">.jp</font>"];
564+ unstyledLeaves: layout.state == "kana" ? ["、", "。", "!", "?"] : [".", ",", ".com", ".jp"];
565+ annotation: layout.state == "kana" ? "" : ".com .jp"
566+ }
567+ CommitKey { id: enterKey; width: panel.keyWidth; }
568+ }
569+ } // column
570+}
571
572=== added directory 'plugins/ja/qml/keys'
573=== added file 'plugins/ja/qml/keys/CommitKey.qml'
574--- plugins/ja/qml/keys/CommitKey.qml 1970-01-01 00:00:00 +0000
575+++ plugins/ja/qml/keys/CommitKey.qml 2016-02-19 18:07:05 +0000
576@@ -0,0 +1,40 @@
577+/*
578+ * Copyright 2015 Canonical Ltd.
579+ *
580+ * This program is free software; you can redistribute it and/or modify
581+ * it under the terms of the GNU Lesser General Public License as published by
582+ * the Free Software Foundation; version 3.
583+ *
584+ * This program is distributed in the hope that it will be useful,
585+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
586+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
587+ * GNU Lesser General Public License for more details.
588+ *
589+ * You should have received a copy of the GNU Lesser General Public License
590+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
591+ */
592+
593+import QtQuick 2.4
594+import "key_constants.js" as UI
595+import keys 1.0
596+
597+ActionKey {
598+ property var actionKeyOverride: maliit_input_method.actionKeyOverride
599+ property string overrideIconName: actionKeyOverride && actionKeyOverride.icon ? actionKeyOverride.icon : ""
600+ property string overrideLabel: actionKeyOverride && actionKeyOverride.label ? actionKeyOverride.label : ""
601+
602+ enabled: actionKeyOverride ? actionKeyOverride.enabled : true
603+ // overrideIcon has high priority over label
604+ label: overrideIconName == "" ? overrideLabel : ""
605+ // Scale the font so the label fits if a long word is set
606+ fontSize: units.gu(UI.symbolShiftKeyFontSize) * (4 / (label.length >= 4 ? (label.length <= 6 ? label.length : 6) : 4));
607+ shifted: label
608+
609+ iconNormal: (overrideIconName == "") && (overrideLabel == "") ? "keyboard-return" : overrideIconName
610+ iconShifted: iconNormal
611+ iconCapsLock: iconNormal
612+
613+ action: maliit_input_method.preedit != "" ? "commit" : "return"
614+ switchBackFromSymbols: true
615+ // TODO: input_method.actionKeyOverride.highlighted
616+}
617
618=== added file 'plugins/ja/qml/keys/CursorKey.qml'
619--- plugins/ja/qml/keys/CursorKey.qml 1970-01-01 00:00:00 +0000
620+++ plugins/ja/qml/keys/CursorKey.qml 2016-02-19 18:07:05 +0000
621@@ -0,0 +1,58 @@
622+/*
623+ * Copyright 2015 Canonical Ltd.
624+ *
625+ * This program is free software; you can redistribute it and/or modify
626+ * it under the terms of the GNU Lesser General Public License as published by
627+ * the Free Software Foundation; version 3.
628+ *
629+ * This program is distributed in the hope that it will be useful,
630+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
631+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
632+ * GNU Lesser General Public License for more details.
633+ *
634+ * You should have received a copy of the GNU Lesser General Public License
635+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
636+ */
637+
638+import QtQuick 2.4
639+import "key_constants.js" as UI
640+import keys 1.0
641+
642+ActionKey {
643+ label: action == "left" ? "⬅" : "➡";
644+ leftSide: action == "left";
645+ rightSide: action == "right";
646+
647+ property string preedit: maliit_input_method.preedit
648+ property int cursorPosition: maliit_input_method.cursorPosition
649+ property bool isPreedit: preedit != ""
650+
651+ overridePressArea: true;
652+
653+ onReleased: {
654+ if (isPreedit) {
655+ if (action == "left" && cursorPosition > 0) {
656+ maliit_input_method.cursorPosition--
657+ } else if (action == "right" && cursorPosition < preedit.length) {
658+ maliit_input_method.cursorPosition++
659+ }
660+ } else {
661+ event_handler.onKeyReleased("", action);
662+ }
663+ }
664+
665+ onPressed: {
666+ if (maliit_input_method.useAudioFeedback)
667+ audioFeedback.play();
668+
669+ if (maliit_input_method.useHapticFeedback)
670+ pressEffect.start();
671+
672+ if (!isPreedit)
673+ event_handler.onKeyPressed("", action);
674+ }
675+
676+ onPressAndHold: {
677+ return;
678+ }
679+}
680
681=== added file 'plugins/ja/qml/keys/DomainKey.qml'
682--- plugins/ja/qml/keys/DomainKey.qml 1970-01-01 00:00:00 +0000
683+++ plugins/ja/qml/keys/DomainKey.qml 2016-02-19 18:07:05 +0000
684@@ -0,0 +1,42 @@
685+/*
686+ * Copyright 2015 Canonical Ltd.
687+ *
688+ * This program is free software; you can redistribute it and/or modify
689+ * it under the terms of the GNU Lesser General Public License as published by
690+ * the Free Software Foundation; version 3.
691+ *
692+ * This program is distributed in the hope that it will be useful,
693+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
694+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
695+ * GNU Lesser General Public License for more details.
696+ *
697+ * You should have received a copy of the GNU Lesser General Public License
698+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
699+ */
700+
701+import QtQuick 2.4
702+import QtMultimedia 5.0
703+import Ubuntu.Components 1.3
704+import Ubuntu.Components.Popups 1.3
705+
706+import "key_constants.js" as UI
707+
708+FlickCharKey {
709+ property var unstyledLeaves: ["", "", "", "", ""];
710+
711+ overridePressArea: true
712+
713+ onReleased: {
714+ event_handler.onKeyReleased(unstyledLeaves[index], action);
715+ }
716+
717+ onPressed: {
718+ if (maliit_input_method.useAudioFeedback)
719+ audioFeedback.play();
720+
721+ if (maliit_input_method.useHapticFeedback)
722+ pressEffect.start();
723+
724+ event_handler.onKeyPressed(unstyledLeaves[index], action);
725+ }
726+}
727
728=== added file 'plugins/ja/qml/keys/FlickArea.qml'
729--- plugins/ja/qml/keys/FlickArea.qml 1970-01-01 00:00:00 +0000
730+++ plugins/ja/qml/keys/FlickArea.qml 2016-02-19 18:07:05 +0000
731@@ -0,0 +1,79 @@
732+/*
733+ * Copyright 2015 Canonical Ltd.
734+ *
735+ * This program is free software; you can redistribute it and/or modify
736+ * it under the terms of the GNU General Public License as published by
737+ * the Free Software Foundation; version 3.
738+ *
739+ * This program is distributed in the hope that it will be useful,
740+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
741+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
742+ * GNU General Public License for more details.
743+ *
744+ * You should have received a copy of the GNU General Public License
745+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
746+ */
747+
748+import QtQuick 2.4
749+
750+MultiPointTouchArea {
751+ id: root
752+
753+ /// Is true while the area is touched, and the finger did not yet lift
754+ property bool pressed: false
755+
756+ /// Cancels the current pressed state of the mouse are
757+ function cancelPress() {
758+ pressed = false;
759+ }
760+
761+ onPressed: {
762+ index = 0;
763+ pressed = true;
764+ rad = 0
765+ }
766+
767+ onReleased: {
768+ pressed = false;
769+ }
770+
771+ property int index: 0 // 0:center, 1:left, 2:top, 3:right, 4:bottom
772+ property int old_index: 0
773+ property real posX: point.x - parent.width / 2
774+ property real posY: point.y - parent.height / 2
775+ property real rad: 0
776+
777+ touchPoints: [
778+ TouchPoint { id: point }
779+ ]
780+
781+ onUpdated: {
782+ rad = Math.atan2(posY, posX)
783+ if ((posX * posX + posY * posY) < (0.5 * parent.height * 0.5 * parent.height)) {
784+ index = 0
785+ } else {
786+ if (rad < -Math.PI / 4.0) {
787+ if (rad < -Math.PI * 3.0 / 4.0) {
788+ index = 1
789+ } else {
790+ index = 2
791+ }
792+ } else if (rad > Math.PI / 4.0) {
793+ if (rad > Math.PI * 3.0 / 4.0) {
794+ index = 1
795+ } else {
796+ index = 4
797+ }
798+ } else {
799+ index = 3
800+ }
801+ }
802+
803+ if (old_index != index) {
804+ old_index = index
805+
806+ if (maliit_input_method.useHapticFeedback)
807+ pressEffect.start();
808+ }
809+ }
810+}
811
812=== added file 'plugins/ja/qml/keys/FlickCharKey.qml'
813--- plugins/ja/qml/keys/FlickCharKey.qml 1970-01-01 00:00:00 +0000
814+++ plugins/ja/qml/keys/FlickCharKey.qml 2016-02-19 18:07:05 +0000
815@@ -0,0 +1,178 @@
816+/*
817+ * Copyright 2015 Canonical Ltd.
818+ *
819+ * This program is free software; you can redistribute it and/or modify
820+ * it under the terms of the GNU Lesser General Public License as published by
821+ * the Free Software Foundation; version 3.
822+ *
823+ * This program is distributed in the hope that it will be useful,
824+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
825+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
826+ * GNU Lesser General Public License for more details.
827+ *
828+ * You should have received a copy of the GNU Lesser General Public License
829+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
830+ */
831+
832+import QtQuick 2.4
833+import QtMultimedia 5.0
834+import Ubuntu.Components 1.3
835+import Ubuntu.Components.Popups 1.3
836+
837+import "key_constants.js" as UI
838+
839+Item {
840+ id: key
841+
842+ property int padding: 0
843+
844+ width: leftSide || rightSide ? panel.keyWidth * 2 : panel.keyWidth
845+ height: panel.keyHeight
846+
847+ /* to be set in keyboard layouts */
848+ property string label: "";
849+ property var leaves: ["", "", "", "", ""];
850+ property int index: keyFlickArea.index;
851+ property bool highlight: false;
852+
853+ property string action
854+ property bool noMagnifier: false
855+ property bool skipAutoCaps: false
856+ property bool switchBackFromSymbols: false
857+
858+ property bool leftSide: false
859+ property bool rightSide: false
860+
861+ property double rowMargin: fullScreenItem.tablet ? units.gu(UI.tabletRowMargin)
862+ : (fullScreenItem.landscape ? units.dp(UI.phoneRowMarginLandscape)
863+ : units.dp(UI.phoneRowMarginPortrait))
864+ property double keyMargin: fullScreenItem.tablet ? units.gu(UI.tabletKeyMargins)
865+ : units.gu(UI.phoneKeyMargins)
866+
867+ // These properties are used by autopilot to determine the visible
868+ // portion of the key to press
869+ readonly property double leftOffset: buttonRect.anchors.leftMargin
870+ readonly property double rightOffset: buttonRect.anchors.rightMargin
871+
872+ /* design */
873+ property string normalColor: UI.charKeyColor
874+ property string pressedColor: UI.charKeyPressedColor
875+ property int fontSize: (fullScreenItem.landscape ? (height / 2) : (height / 2.8));
876+
877+ /// annotation shows a small label in the upper right corner
878+ // if the annotiation property is set, it will be used. If not, the first position in extended[] list or extendedShifted[] list will
879+ // be used, depending on the state. If no extended/extendedShifted arrays exist, no annotation is shown
880+ property string annotation: ""
881+
882+ /*! indicates if te key is currently pressed/down*/
883+ property alias currentlyPressed: keyFlickArea.pressed
884+
885+ property string oskState: panel.activeKeypadState
886+
887+ // Allow action keys to override the standard key behaviour
888+ property bool overridePressArea: false
889+
890+ signal pressed()
891+ signal released()
892+
893+ // Make it possible for the visible area of the key to differ from the
894+ // actual key size. This allows us to extend the touch area of the bottom
895+ // row of keys all the way to the bottom of the keyboard, whilst
896+ // maintaining the same visual appearance.
897+ Item {
898+ anchors.top: parent.top
899+ height: panel.keyHeight
900+ width: parent.width
901+
902+ Rectangle {
903+ id: buttonRect
904+ color: key.currentlyPressed || key.highlight ? pressedColor : normalColor
905+ anchors.fill: parent
906+ anchors.leftMargin: key.leftSide ? (parent.width - panel.keyWidth) + key.keyMargin : key.keyMargin
907+ anchors.rightMargin: key.rightSide ? (parent.width - panel.keyWidth) + key.keyMargin : key.keyMargin
908+ anchors.bottomMargin: key.rowMargin
909+ radius: units.dp(4)
910+
911+ /// label of the key
912+ // the label is also the value subitted to the app
913+
914+ Column {
915+ spacing: units.gu( UI.annotationMargins )
916+ anchors.centerIn: parent
917+
918+ Text {
919+ id: keyLabel
920+ text: label
921+ anchors.horizontalCenter: parent.horizontalCenter
922+ font.family: UI.fontFamily
923+ font.pixelSize: fontSize
924+ font.weight: Font.Light
925+ color: UI.fontColor
926+ textFormat: Text.StyledText
927+ }
928+
929+ Text {
930+ id: annotationLabel
931+ text: annotation
932+
933+ anchors.horizontalCenter: parent.horizontalCenter
934+ anchors.bottomMargin: units.gu( UI.annotationMargins )
935+
936+ font.family: UI.annotationFont
937+ font.pixelSize: fullScreenItem.tablet ? units.dp(UI.tabletAnnotationFontSize) : units.dp(UI.phoneAnnotationFontSize)
938+ font.weight: Font.Light
939+ color: UI.annotationFontColor
940+ visible: annotation != ""
941+ }
942+ }
943+ }
944+
945+ FlickPop {
946+ anchors.horizontalCenter: buttonRect.horizontalCenter
947+ anchors.bottom: buttonRect.top
948+ anchors.bottomMargin: key.height * 0.5
949+ width: units.gu((UI.fontSize + UI.flickMargin) * 3)
950+ height: units.gu((UI.fontSize + UI.flickMargin) * 3)
951+ chars: leaves
952+ index: keyFlickArea.index
953+ visible: key.currentlyPressed && chars.length > 1
954+ }
955+ }
956+
957+ FlickArea {
958+ id: keyFlickArea
959+ anchors.fill: key
960+
961+ onReleased: {
962+ if (overridePressArea) {
963+ key.released();
964+ return;
965+ }
966+
967+ event_handler.onKeyReleased(leaves[index], action);
968+ }
969+
970+ onPressed: {
971+ if (overridePressArea) {
972+ key.pressed();
973+ return;
974+ }
975+
976+ if (maliit_input_method.useAudioFeedback)
977+ audioFeedback.play();
978+
979+ if (maliit_input_method.useHapticFeedback)
980+ pressEffect.start();
981+
982+ event_handler.onKeyPressed(leaves[index], action);
983+ }
984+ }
985+
986+ Connections {
987+ target: swipeArea.drag
988+ onActiveChanged: {
989+ if (swipeArea.drag.active)
990+ keyFlickArea.cancelPress();
991+ }
992+ }
993+}
994
995=== added file 'plugins/ja/qml/keys/FlickPop.qml'
996--- plugins/ja/qml/keys/FlickPop.qml 1970-01-01 00:00:00 +0000
997+++ plugins/ja/qml/keys/FlickPop.qml 2016-02-19 18:07:05 +0000
998@@ -0,0 +1,70 @@
999+/*
1000+ * Copyright 2015 Canonical Ltd.
1001+ *
1002+ * This program is free software; you can redistribute it and/or modify
1003+ * it under the terms of the GNU General Public License as published by
1004+ * the Free Software Foundation; version 3.
1005+ *
1006+ * This program is distributed in the hope that it will be useful,
1007+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1008+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1009+ * GNU General Public License for more details.
1010+ *
1011+ * You should have received a copy of the GNU General Public License
1012+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1013+ */
1014+
1015+import QtQuick 2.4
1016+import Ubuntu.Components 1.3
1017+
1018+import "key_constants.js" as UI
1019+
1020+/*!
1021+ Item to show a "bubble" with a text in the center.
1022+ The bottom center is where the bubble points to, and it animates to that position
1023+ when hiding it.
1024+ */
1025+Item {
1026+ id: root
1027+
1028+ property var chars
1029+ property int index: 0
1030+
1031+ visible: false
1032+
1033+ FlickPopKey {
1034+ id: center
1035+ labelChar: chars[0]
1036+ anchors.centerIn: parent
1037+ labelOpacity: index == 0 ? 1.0 : 0.6
1038+ labelColor: index == 0 ? UbuntuColors.orange : UI.fontColor
1039+ }
1040+ FlickPopKey {
1041+ labelChar: chars[1] ? chars[1] : ""
1042+ anchors.verticalCenter: center.verticalCenter
1043+ anchors.right: center.left
1044+ labelOpacity: index == 1 ? 1.0 : 0.6
1045+ labelColor: index == 1 ? UbuntuColors.orange : UI.fontColor
1046+ }
1047+ FlickPopKey {
1048+ labelChar: chars[2] ? chars[2] : ""
1049+ anchors.horizontalCenter: center.horizontalCenter
1050+ anchors.bottom: center.top
1051+ labelOpacity: index == 2 ? 1.0 : 0.6
1052+ labelColor: index == 2 ? UbuntuColors.orange : UI.fontColor
1053+ }
1054+ FlickPopKey {
1055+ labelChar: chars[3] ? chars[3] : ""
1056+ anchors.verticalCenter: center.verticalCenter
1057+ anchors.left: center.right
1058+ labelOpacity: index == 3 ? 1.0 : 0.6
1059+ labelColor: index == 3 ? UbuntuColors.orange : UI.fontColor
1060+ }
1061+ FlickPopKey {
1062+ labelChar: chars[4] ? chars[4] : ""
1063+ anchors.horizontalCenter: center.horizontalCenter
1064+ anchors.top: center.bottom
1065+ labelOpacity: index == 4 ? 1.0 : 0.6
1066+ labelColor: index == 4 ? UbuntuColors.orange : UI.fontColor
1067+ }
1068+}
1069
1070=== added file 'plugins/ja/qml/keys/FlickPopKey.qml'
1071--- plugins/ja/qml/keys/FlickPopKey.qml 1970-01-01 00:00:00 +0000
1072+++ plugins/ja/qml/keys/FlickPopKey.qml 2016-02-19 18:07:05 +0000
1073@@ -0,0 +1,42 @@
1074+/*
1075+ * Copyright 2015 Canonical Ltd.
1076+ *
1077+ * This program is free software; you can redistribute it and/or modify
1078+ * it under the terms of the GNU General Public License as published by
1079+ * the Free Software Foundation; version 3.
1080+ *
1081+ * This program is distributed in the hope that it will be useful,
1082+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1083+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1084+ * GNU General Public License for more details.
1085+ *
1086+ * You should have received a copy of the GNU General Public License
1087+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1088+ */
1089+
1090+import QtQuick 2.4
1091+import "key_constants.js" as UI
1092+
1093+Rectangle {
1094+ width: units.gu(UI.fontSize + UI.flickMargin)
1095+ height: units.gu(UI.fontSize + UI.flickMargin)
1096+
1097+ property string labelChar
1098+ property color labelColor: UI.fontColor
1099+ property real labelOpacity: 1.0
1100+ visible: labelChar ? true : false
1101+
1102+ border.width: units.gu(UI.flickBorderWidth)
1103+ border.color: UI.flickBorderColor
1104+ radius: width / 10
1105+
1106+ Text {
1107+ anchors.centerIn: parent
1108+ text: parent.labelChar
1109+ font.family: UI.fontFamily
1110+ font.pixelSize: units.gu(UI.fontSize)
1111+ font.bold: UI.fontBold
1112+ color: parent.labelColor
1113+ opacity: parent.labelOpacity
1114+ }
1115+}
1116
1117=== added file 'plugins/ja/qml/keys/KanaSwitchKey.qml'
1118--- plugins/ja/qml/keys/KanaSwitchKey.qml 1970-01-01 00:00:00 +0000
1119+++ plugins/ja/qml/keys/KanaSwitchKey.qml 2016-02-19 18:07:05 +0000
1120@@ -0,0 +1,85 @@
1121+/*
1122+ * Copyright 2015 Canonical Ltd.
1123+ *
1124+ * This program is free software; you can redistribute it and/or modify
1125+ * it under the terms of the GNU Lesser General Public License as published by
1126+ * the Free Software Foundation; version 3.
1127+ *
1128+ * This program is distributed in the hope that it will be useful,
1129+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1130+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1131+ * GNU Lesser General Public License for more details.
1132+ *
1133+ * You should have received a copy of the GNU Lesser General Public License
1134+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1135+ */
1136+
1137+import QtQuick 2.4
1138+import QtMultimedia 5.0
1139+import Ubuntu.Components 1.3
1140+import Ubuntu.Components.Popups 1.3
1141+
1142+import "key_constants.js" as UI
1143+
1144+FlickCharKey {
1145+ padding: UI.actionKeyPadding
1146+ label: kana.label
1147+ leaves: ["↻", "", "あ", "A"]
1148+ normalColor: UI.actionKeyColor
1149+ pressedColor: UI.actionKeyPressedColor
1150+
1151+ overridePressArea: true
1152+
1153+ property bool isPreedit: maliit_input_method.preedit.length > 0
1154+ property string default_state: "kana"
1155+
1156+ state: kana.state
1157+
1158+ Item {
1159+ id: kana
1160+ property string label: "あ/A"
1161+
1162+ state: parent.default_state;
1163+ states: [
1164+ State {
1165+ name: "kana"
1166+ PropertyChanges {
1167+ target: kana;
1168+ label: "<font color=\"" + UbuntuColors.orange + "\">あ</font>/A";
1169+ state: "kana";
1170+ }
1171+ },
1172+ State {
1173+ name: "alnum"
1174+ PropertyChanges {
1175+ target: kana;
1176+ label: "あ/<font color=\"" + UbuntuColors.orange + "\">A</font>";
1177+ state: "alnum";
1178+ }
1179+ }
1180+ ]
1181+ }
1182+
1183+ onReleased: {
1184+ if (isPreedit) {
1185+ event_handler.onKeyReleased("", "commit");
1186+ }
1187+ if (index == 0) {
1188+ kana.state = kana.state == "kana" ? "alnum" : "kana"
1189+ } else {
1190+ if (index == 2) {
1191+ kana.state = "kana"
1192+ } else if (index == 3) {
1193+ kana.state = "alnum"
1194+ }
1195+ }
1196+ }
1197+
1198+ onPressed: {
1199+ if (maliit_input_method.useAudioFeedback)
1200+ audioFeedback.play();
1201+
1202+ if (maliit_input_method.useHapticFeedback)
1203+ pressEffect.start();
1204+ }
1205+}
1206
1207=== added file 'plugins/ja/qml/keys/ModifierKey.qml'
1208--- plugins/ja/qml/keys/ModifierKey.qml 1970-01-01 00:00:00 +0000
1209+++ plugins/ja/qml/keys/ModifierKey.qml 2016-02-19 18:07:05 +0000
1210@@ -0,0 +1,79 @@
1211+/*
1212+ * Copyright 2015 Canonical Ltd.
1213+ *
1214+ * This program is free software; you can redistribute it and/or modify
1215+ * it under the terms of the GNU Lesser General Public License as published by
1216+ * the Free Software Foundation; version 3.
1217+ *
1218+ * This program is distributed in the hope that it will be useful,
1219+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1220+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1221+ * GNU Lesser General Public License for more details.
1222+ *
1223+ * You should have received a copy of the GNU Lesser General Public License
1224+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1225+ */
1226+
1227+import QtQuick 2.4
1228+import QtMultimedia 5.0
1229+import Ubuntu.Components 1.3
1230+import Ubuntu.Components.Popups 1.3
1231+
1232+import "modifier.js" as Modifier
1233+import "key_constants.js" as UI
1234+
1235+FlickCharKey {
1236+ label: (isPreedit && layoutState == "kana") ? " ゛ ゜" : "␣"
1237+ leaves: isPreedit ? preeditLeaves : ["␣", "□"]
1238+ annotation: isPreedit ? "大⇔小" : ""
1239+ fontSize: isPreedit ? units.gu( UI.fontSize ) * 0.8 : units.gu( UI.fontSize )
1240+
1241+ overridePressArea: true
1242+
1243+ property string layoutState: "kana"
1244+ property string preedit: maliit_input_method.preedit
1245+ property int cursorPosition: maliit_input_method.cursorPosition
1246+ property bool isPreedit: preedit != ""
1247+ property string lastChar: ""
1248+ property var preeditLeaves: Modifier.map[lastChar] ? Modifier.map[lastChar] : [lastChar]
1249+
1250+ onReleased: {
1251+ if (isPreedit) {
1252+ if (layoutState == "alnum") {
1253+ if (index != 0) {
1254+ event_handler.onKeyReleased("", "space");
1255+ } else {
1256+ var pos = cursorPosition
1257+ var newChar = lastChar.charCodeAt(0) < 91 ? lastChar.toLowerCase() : lastChar.toUpperCase()
1258+ maliit_input_method.preedit = preedit.substr(0, cursorPosition-1) + newChar + preedit.substr(cursorPosition)
1259+ maliit_input_method.cursorPosition = pos
1260+ }
1261+ } else if (preeditLeaves[index] && preeditLeaves[index] != "") {
1262+ var pos = cursorPosition
1263+ maliit_input_method.preedit = preedit.substr(0, cursorPosition-1) + preeditLeaves[index] + preedit.substr(cursorPosition)
1264+ maliit_input_method.cursorPosition = pos
1265+ }
1266+ } else {
1267+ if (index == 0) {
1268+ event_handler.onKeyReleased("", "space");
1269+ } else {
1270+ event_handler.onKeyReleased(" ", "");
1271+ }
1272+ }
1273+ }
1274+
1275+ onPressed: {
1276+ if (maliit_input_method.useAudioFeedback)
1277+ audioFeedback.play();
1278+
1279+ if (maliit_input_method.useHapticFeedback)
1280+ pressEffect.start();
1281+
1282+ if (isPreedit) {
1283+ lastChar = preedit.charAt(cursorPosition-1)
1284+ if (!Modifier.map[lastChar] && Modifier.normalize[lastChar]) {
1285+ lastChar = Modifier.normalize[lastChar]
1286+ }
1287+ }
1288+ }
1289+}
1290
1291=== added file 'plugins/ja/qml/keys/UndoKey.qml'
1292--- plugins/ja/qml/keys/UndoKey.qml 1970-01-01 00:00:00 +0000
1293+++ plugins/ja/qml/keys/UndoKey.qml 2016-02-19 18:07:05 +0000
1294@@ -0,0 +1,25 @@
1295+/*
1296+ * Copyright 2015 Canonical Ltd.
1297+ *
1298+ * This program is free software; you can redistribute it and/or modify
1299+ * it under the terms of the GNU Lesser General Public License as published by
1300+ * the Free Software Foundation; version 3.
1301+ *
1302+ * This program is distributed in the hope that it will be useful,
1303+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1304+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1305+ * GNU Lesser General Public License for more details.
1306+ *
1307+ * You should have received a copy of the GNU Lesser General Public License
1308+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1309+ */
1310+
1311+import QtQuick 2.4
1312+import "key_constants.js" as UI
1313+import keys 1.0
1314+
1315+ActionKey {
1316+ label: "戻す";
1317+ action: "undo";
1318+ fontSize: units.gu(UI.undoFontSize);
1319+}
1320
1321=== added file 'plugins/ja/qml/keys/key_constants.js'
1322--- plugins/ja/qml/keys/key_constants.js 1970-01-01 00:00:00 +0000
1323+++ plugins/ja/qml/keys/key_constants.js 2016-02-19 18:07:05 +0000
1324@@ -0,0 +1,31 @@
1325+/*
1326+ * Copyright 2015 Canonical Ltd.
1327+ *
1328+ * This program is free software; you can redistribute it and/or modify
1329+ * it under the terms of the GNU General Public License as published by
1330+ * the Free Software Foundation; version 3.
1331+ *
1332+ * This program is distributed in the hope that it will be useful,
1333+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1334+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1335+ * GNU General Public License for more details.
1336+ *
1337+ * You should have received a copy of the GNU General Public License
1338+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1339+ */
1340+
1341+.pragma library
1342+
1343+Qt.include("../../../keys/key_constants.js")
1344+
1345+/* ActionKey layout */
1346+var undoFontSize = 2;
1347+
1348+/* FlickCharKey layout */
1349+var annotationFontSize = 1.5; // gu
1350+var annotationMargins = 0.3; // gu
1351+
1352+/* FlickPop layout */
1353+var flickMargin = 1.5 // gu
1354+var flickBorderWidth = 0.1 // gu
1355+var flickBorderColor = "#999999"
1356
1357=== added file 'plugins/ja/qml/keys/modifier.js'
1358--- plugins/ja/qml/keys/modifier.js 1970-01-01 00:00:00 +0000
1359+++ plugins/ja/qml/keys/modifier.js 2016-02-19 18:07:05 +0000
1360@@ -0,0 +1,102 @@
1361+/*
1362+ * Copyright 2015 Canonical Ltd.
1363+ *
1364+ * This program is free software; you can redistribute it and/or modify
1365+ * it under the terms of the GNU General Public License as published by
1366+ * the Free Software Foundation; version 3.
1367+ *
1368+ * This program is distributed in the hope that it will be useful,
1369+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1370+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1371+ * GNU General Public License for more details.
1372+ *
1373+ * You should have received a copy of the GNU General Public License
1374+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1375+ */
1376+
1377+.pragma library
1378+
1379+/*
1380+ * Modified character map for ModifierKey
1381+ *
1382+ * ModifierKey modify a charcter by left/right/up swipe. This is character map
1383+ * and swipe direction.
1384+ * map[ORIGIN KEY] = [NO MODIFY, LEFT, UP, RIGHT]
1385+ */
1386+var map = {}
1387+map["あ"] = ["あ", "", "ぁ", ""]
1388+map["い"] = ["い", "", "ぃ", ""]
1389+map["う"] = ["う", "ヴ", "ぅ", ""]
1390+map["え"] = ["え", "", "ぇ", ""]
1391+map["お"] = ["お", "", "ぉ", ""]
1392+map["か"] = ["か", "が", "", ""]
1393+map["き"] = ["き", "ぎ", "", ""]
1394+map["く"] = ["く", "ぐ", "", ""]
1395+map["け"] = ["け", "げ", "", ""]
1396+map["こ"] = ["こ", "ご", "", ""]
1397+map["さ"] = ["さ", "ざ", "", ""]
1398+map["し"] = ["し", "じ", "", ""]
1399+map["す"] = ["す", "ず", "", ""]
1400+map["せ"] = ["せ", "ぜ", "", ""]
1401+map["そ"] = ["そ", "ぞ", "", ""]
1402+map["た"] = ["た", "だ", "", ""]
1403+map["ち"] = ["ち", "ぢ", "", ""]
1404+map["つ"] = ["つ", "づ", "っ", ""]
1405+map["て"] = ["て", "で", "", ""]
1406+map["と"] = ["と", "ど", "", ""]
1407+map["は"] = ["は", "ば", "", "ぱ"]
1408+map["ひ"] = ["ひ", "び", "", "ぴ"]
1409+map["ふ"] = ["ふ", "ぶ", "", "ぷ"]
1410+map["へ"] = ["へ", "べ", "", "ぺ"]
1411+map["ほ"] = ["ほ", "ぼ", "", "ぽ"]
1412+map["や"] = ["や", "", "ゃ", ""]
1413+map["("] = ["(", "「", "『", "【"]
1414+map["ゆ"] = ["ゆ", "", "ゅ", ""]
1415+map[")"] = [")", "」", "』", "】"]
1416+map["よ"] = ["よ", "", "ょ", ""]
1417+map["わ"] = ["わ", "ゐ", "ゎ", "ゑ"]
1418+map["ー"] = ["ー", "=", "~", "+"]
1419+map["、"] = ["、", "・", "…", "@"]
1420+map["。"] = ["。", ":", ";", "♪"]
1421+
1422+/*
1423+ * Reverse map for ModifierKey map
1424+ *
1425+ * This map is reverse map for modified characters.
1426+ */
1427+var normalize = {}
1428+normalize["ぁ"] = "あ"
1429+normalize["ぃ"] = "い"
1430+normalize["ヴ"] = "う"; normalize["ぅ"] = "う"
1431+normalize["ぇ"] = "え"
1432+normalize["ぉ"] = "お"
1433+normalize["が"] = "か"
1434+normalize["ぎ"] = "き"
1435+normalize["ぐ"] = "く"
1436+normalize["げ"] = "け"
1437+normalize["ご"] = "こ"
1438+normalize["ざ"] = "さ"
1439+normalize["じ"] = "し"
1440+normalize["ず"] = "す"
1441+normalize["ぜ"] = "せ"
1442+normalize["ぞ"] = "そ"
1443+normalize["だ"] = "た"
1444+normalize["ぢ"] = "ち"
1445+normalize["づ"] = "つ"; normalize["っ"] = "つ"
1446+normalize["で"] = "て"
1447+normalize["ど"] = "と"
1448+normalize["ば"] = "は"; normalize["ぱ"] = "は"
1449+normalize["び"] = "ひ"; normalize["ぴ"] = "ひ"
1450+normalize["ぶ"] = "ふ"; normalize["ぷ"] = "ふ"
1451+normalize["べ"] = "へ"; normalize["ぺ"] = "へ"
1452+normalize["ぼ"] = "ほ"; normalize["ぽ"] = "ほ"
1453+normalize["ゃ"] = "や"
1454+normalize["「"] = "("; normalize["『"] = "("; normalize["【"] = "("
1455+normalize["ゅ"] = "ゆ"
1456+normalize["」"] = ")"; normalize["』"] = ")"; normalize["】"] = ")"
1457+normalize["ょ"] = "よ"
1458+normalize["ゐ"] = "わ"; normalize["ゎ"] = "わ"; normalize["ゑ"] = "わ"
1459+normalize["="] = "ー"; normalize["~"] = "ー"; normalize["+"] = "ー"
1460+normalize["・"] = "、"; normalize["…"] = "、"; normalize["@"] = "、"
1461+normalize[":"] = "。"; normalize[";"] = "。"; normalize["♪"] = "。"
1462+
1463
1464=== added file 'plugins/ja/qml/qml.pro'
1465--- plugins/ja/qml/qml.pro 1970-01-01 00:00:00 +0000
1466+++ plugins/ja/qml/qml.pro 2016-02-19 18:07:05 +0000
1467@@ -0,0 +1,31 @@
1468+TOP_BUILDDIR = $$OUT_PWD/../../..
1469+TOP_SRCDIR = $$PWD/../../..
1470+
1471+include($${TOP_SRCDIR}/config.pri)
1472+
1473+TARGET = dummy
1474+TEMPLATE = lib
1475+
1476+lang_ja.path = "$$UBUNTU_KEYBOARD_LIB_DIR/ja/"
1477+lang_ja.files = *.qml *.js
1478+
1479+lang_ja_keys.path = "$$UBUNTU_KEYBOARD_LIB_DIR/ja/keys"
1480+lang_ja_keys.files = keys/*.qml keys/*.js
1481+
1482+INSTALLS += lang_ja lang_ja_keys
1483+
1484+# for QtCreator
1485+OTHER_FILES += \
1486+ Keyboard_ja.qml \
1487+ Keyboard_ja_email.qml \
1488+ Keyboard_ja_url.qml \
1489+ Keyboard_ja_url_search.qml \
1490+ keys/CommitKey.qml \
1491+ keys/CursorKey.qml \
1492+ keys/FlickArea.qml \
1493+ keys/FlickCharKey.qml \
1494+ keys/FlickPop.qml \
1495+ keys/FlickPopKey.qml \
1496+ keys/KanaSwitchKey.qml \
1497+ keys/ModifierKey.qml \
1498+ keys/UndoKey.qml
1499
1500=== added directory 'plugins/ja/src'
1501=== added file 'plugins/ja/src/anthyadapter.cpp'
1502--- plugins/ja/src/anthyadapter.cpp 1970-01-01 00:00:00 +0000
1503+++ plugins/ja/src/anthyadapter.cpp 2016-02-19 18:07:05 +0000
1504@@ -0,0 +1,117 @@
1505+/*
1506+ * Copyright 2015 Canonical Ltd.
1507+ *
1508+ * This program is free software; you can redistribute it and/or modify
1509+ * it under the terms of the GNU Lesser General Public License as published by
1510+ * the Free Software Foundation; version 3.
1511+ *
1512+ * This program is distributed in the hope that it will be useful,
1513+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1514+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515+ * GNU Lesser General Public License for more details.
1516+ *
1517+ * You should have received a copy of the GNU Lesser General Public License
1518+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1519+ */
1520+
1521+#include "anthyadapter.h"
1522+
1523+#include <QDebug>
1524+
1525+#ifdef JA_DEBUG
1526+static void anthy_log(int level, const char *log)
1527+{
1528+ Q_UNUSED(level)
1529+
1530+ qWarning() << "[anthy]: " << QString(log);
1531+}
1532+#endif
1533+
1534+AnthyAdapter::AnthyAdapter(QObject *parent) :
1535+ QObject(parent)
1536+{
1537+#ifdef JA_DEBUG
1538+ anthy_set_logger(anthy_log, 0);
1539+#endif
1540+ if (anthy_init() < 0)
1541+ qCritical() << "[anthy] failed to init.";
1542+
1543+ m_context = anthy_create_context();
1544+ if (m_context == 0)
1545+ qCritical() << "[anthy] failed to create anthy context.";
1546+
1547+ anthy_context_set_encoding(m_context, ANTHY_UTF8_ENCODING);
1548+}
1549+
1550+AnthyAdapter::~AnthyAdapter()
1551+{
1552+ anthy_release_context(m_context);
1553+ anthy_quit();
1554+}
1555+
1556+#define CANDIDATE_SIZE 1024
1557+void AnthyAdapter::parse(const QString& string)
1558+{
1559+ struct anthy_conv_stat cs;
1560+ struct anthy_segment_stat ss;
1561+ char buf[CANDIDATE_SIZE];
1562+ QString candidate, trail;
1563+
1564+ if (anthy_set_string(m_context, string.toUtf8().constData()) != 0) {
1565+ qCritical() << "[anthy] failed to set string: " << string;
1566+ }
1567+
1568+ if (anthy_get_stat(m_context, &cs) != 0) {
1569+ qCritical() << "[anthy] failed to get stat: " << string;
1570+ }
1571+
1572+ if (anthy_get_segment_stat(m_context, 0, &ss) != 0) {
1573+
1574+ qCritical() << "[anthy] failed to get segment stat: " << string;
1575+ }
1576+
1577+ /* Nth segment (N > 0) use only first candidate */
1578+ if (cs.nr_segment > 1) {
1579+ for (int i = 1; i < cs.nr_segment; ++i) {
1580+ if (anthy_get_segment(m_context, i, 0, NULL, 0) > CANDIDATE_SIZE - 1) {
1581+ qCritical() << "[anthy] buffer overflow: " << string;
1582+ continue;
1583+ }
1584+
1585+ if (anthy_get_segment(m_context, i, 0, buf, sizeof(buf)) < 0) {
1586+ qCritical() << "[anthy] failed to get segment: " << string;
1587+ continue;
1588+ }
1589+
1590+ trail.append(buf);
1591+ }
1592+ }
1593+
1594+ /* Create candidate list for 1st segment */
1595+ candidates.clear();
1596+ candidates.append(string);
1597+ for (int i = 0; i < ss.nr_candidate; ++i) {
1598+ if (anthy_get_segment(m_context, 0, i, NULL, 0) > CANDIDATE_SIZE - 1) {
1599+ qCritical() << "[anthy] buffer overflow: " << string;
1600+ continue;
1601+ }
1602+
1603+ if (anthy_get_segment(m_context, 0, i, buf, sizeof(buf)) < 0) {
1604+ qCritical() << "[anthy] failed to get segment: " << string;
1605+ continue;
1606+ }
1607+
1608+ candidate = QString(buf);
1609+ candidate.append(trail);
1610+ candidates.append(candidate);
1611+ }
1612+
1613+ Q_EMIT newPredictionSuggestions(string, candidates);
1614+}
1615+
1616+void AnthyAdapter::wordCandidateSelected(const QString& word)
1617+{
1618+ Q_UNUSED(word)
1619+
1620+ anthy_reset_context(m_context);
1621+}
1622
1623=== added file 'plugins/ja/src/anthyadapter.h'
1624--- plugins/ja/src/anthyadapter.h 1970-01-01 00:00:00 +0000
1625+++ plugins/ja/src/anthyadapter.h 2016-02-19 18:07:05 +0000
1626@@ -0,0 +1,45 @@
1627+/*
1628+ * Copyright 2015 Canonical Ltd.
1629+ *
1630+ * This program is free software; you can redistribute it and/or modify
1631+ * it under the terms of the GNU Lesser General Public License as published by
1632+ * the Free Software Foundation; version 3.
1633+ *
1634+ * This program is distributed in the hope that it will be useful,
1635+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1636+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1637+ * GNU Lesser General Public License for more details.
1638+ *
1639+ * You should have received a copy of the GNU Lesser General Public License
1640+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1641+ */
1642+
1643+#ifndef ANTHYADAPTER_H
1644+#define ANTHYADAPTER_H
1645+
1646+#include <QObject>
1647+#include <QStringList>
1648+
1649+#include "anthy/anthy.h"
1650+
1651+class AnthyAdapter : public QObject
1652+{
1653+ Q_OBJECT
1654+
1655+public:
1656+ explicit AnthyAdapter(QObject *parent = 0);
1657+ ~AnthyAdapter();
1658+
1659+ QStringList candidates;
1660+
1661+signals:
1662+ void newPredictionSuggestions(QString, QStringList);
1663+
1664+public slots:
1665+ void parse(const QString& string);
1666+ void wordCandidateSelected(const QString& word);
1667+
1668+private:
1669+ anthy_context_t m_context;
1670+};
1671+#endif // ANTHYADAPTER_H
1672
1673=== added file 'plugins/ja/src/japaneselanguagefeatures.cpp'
1674--- plugins/ja/src/japaneselanguagefeatures.cpp 1970-01-01 00:00:00 +0000
1675+++ plugins/ja/src/japaneselanguagefeatures.cpp 2016-02-19 18:07:05 +0000
1676@@ -0,0 +1,92 @@
1677+/*
1678+ * Copyright 2015 Canonical Ltd.
1679+ *
1680+ * This program is free software; you can redistribute it and/or modify
1681+ * it under the terms of the GNU Lesser General Public License as published by
1682+ * the Free Software Foundation; version 3.
1683+ *
1684+ * This program is distributed in the hope that it will be useful,
1685+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1686+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1687+ * GNU Lesser General Public License for more details.
1688+ *
1689+ * You should have received a copy of the GNU Lesser General Public License
1690+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1691+ */
1692+
1693+#include "japaneselanguagefeatures.h"
1694+
1695+JapaneseLanguageFeatures::JapaneseLanguageFeatures(QObject *parent) :
1696+ QObject(parent)
1697+{
1698+}
1699+
1700+JapaneseLanguageFeatures::~JapaneseLanguageFeatures()
1701+{
1702+}
1703+
1704+bool JapaneseLanguageFeatures::alwaysShowSuggestions() const
1705+{
1706+ // Japanese characters can only be entered via suggestions.
1707+ return true;
1708+}
1709+
1710+bool JapaneseLanguageFeatures::autoCapsAvailable() const
1711+{
1712+ return false;
1713+}
1714+
1715+bool JapaneseLanguageFeatures::activateAutoCaps(const QString &preedit) const
1716+{
1717+ Q_UNUSED(preedit)
1718+ return false;
1719+}
1720+
1721+QString JapaneseLanguageFeatures::appendixForReplacedPreedit(const QString &preedit) const
1722+{
1723+ Q_UNUSED(preedit)
1724+ // auto add a character in any event?
1725+ return QString("");
1726+}
1727+
1728+bool JapaneseLanguageFeatures::isSeparator(const QString &text) const
1729+{
1730+ static const QString separators = QString::fromUtf8("。、,!?:;.\r\n");
1731+
1732+ if (text.isEmpty()) {
1733+ return false;
1734+ }
1735+
1736+ if (separators.contains(text.right(1))) {
1737+ return true;
1738+ }
1739+
1740+ return false;
1741+}
1742+
1743+bool JapaneseLanguageFeatures::isSymbol(const QString &text) const
1744+{
1745+ Q_UNUSED(text)
1746+
1747+ return false;
1748+}
1749+
1750+bool JapaneseLanguageFeatures::ignoreSimilarity() const
1751+{
1752+ return true;
1753+}
1754+
1755+bool JapaneseLanguageFeatures::wordEngineAvailable() const
1756+{
1757+ return true;
1758+}
1759+
1760+bool JapaneseLanguageFeatures::enablePreeditAtInsertion() const
1761+{
1762+ return true;
1763+}
1764+
1765+bool JapaneseLanguageFeatures::restorePreedit() const
1766+{
1767+ return false;
1768+}
1769
1770=== added file 'plugins/ja/src/japaneselanguagefeatures.h'
1771--- plugins/ja/src/japaneselanguagefeatures.h 1970-01-01 00:00:00 +0000
1772+++ plugins/ja/src/japaneselanguagefeatures.h 2016-02-19 18:07:05 +0000
1773@@ -0,0 +1,42 @@
1774+/*
1775+ * Copyright 2015 Canonical Ltd.
1776+ *
1777+ * This program is free software; you can redistribute it and/or modify
1778+ * it under the terms of the GNU Lesser General Public License as published by
1779+ * the Free Software Foundation; version 3.
1780+ *
1781+ * This program is distributed in the hope that it will be useful,
1782+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1783+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1784+ * GNU Lesser General Public License for more details.
1785+ *
1786+ * You should have received a copy of the GNU Lesser General Public License
1787+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1788+ */
1789+
1790+#ifndef JAPANESELANGUAGEFEATURES_H
1791+#define JAPANESELANGUAGEFEATURES_H
1792+
1793+#include "abstractlanguagefeatures.h"
1794+#include <QObject>
1795+
1796+class JapaneseLanguageFeatures : public QObject, public AbstractLanguageFeatures
1797+{
1798+ Q_OBJECT
1799+public:
1800+ explicit JapaneseLanguageFeatures(QObject *parent = 0);
1801+ virtual ~JapaneseLanguageFeatures();
1802+
1803+ virtual bool alwaysShowSuggestions() const;
1804+ virtual bool autoCapsAvailable() const;
1805+ virtual bool activateAutoCaps(const QString &preedit) const;
1806+ virtual QString appendixForReplacedPreedit(const QString &preedit) const;
1807+ virtual bool isSeparator(const QString &text) const;
1808+ virtual bool isSymbol(const QString &text) const;
1809+ virtual bool ignoreSimilarity() const;
1810+ virtual bool wordEngineAvailable() const;
1811+ virtual bool enablePreeditAtInsertion() const;
1812+ virtual bool restorePreedit() const;
1813+};
1814+
1815+#endif // JAPANESELANGUAGEFEATURES_H
1816
1817=== added file 'plugins/ja/src/japaneseplugin.cpp'
1818--- plugins/ja/src/japaneseplugin.cpp 1970-01-01 00:00:00 +0000
1819+++ plugins/ja/src/japaneseplugin.cpp 2016-02-19 18:07:05 +0000
1820@@ -0,0 +1,59 @@
1821+#include "japaneseplugin.h"
1822+#include "japaneselanguagefeatures.h"
1823+
1824+#include <QDebug>
1825+
1826+JapanesePlugin::JapanesePlugin(QObject *parent) :
1827+ AbstractLanguagePlugin(parent)
1828+ , m_japaneseLanguageFeatures(new JapaneseLanguageFeatures)
1829+ , m_processingWord(false)
1830+{
1831+ m_anthyThread = new QThread();
1832+ m_anthyAdapter = new AnthyAdapter();
1833+ m_anthyAdapter->moveToThread(m_anthyThread);
1834+
1835+ connect(m_anthyAdapter, SIGNAL(newPredictionSuggestions(QString, QStringList)), this, SLOT(finishedProcessing(QString, QStringList)));
1836+ connect(this, SIGNAL(parsePredictionText(QString)), m_anthyAdapter, SLOT(parse(const QString&)));
1837+ connect(this, SIGNAL(candidateSelected(QString)), m_anthyAdapter, SLOT(wordCandidateSelected(const QString&)));
1838+
1839+ m_anthyThread->start();
1840+}
1841+
1842+JapanesePlugin::~JapanesePlugin()
1843+{
1844+ m_anthyAdapter->deleteLater();
1845+ m_anthyThread->quit();
1846+ m_anthyThread->wait();
1847+}
1848+
1849+AbstractLanguageFeatures* JapanesePlugin::languageFeature()
1850+{
1851+ return m_japaneseLanguageFeatures;
1852+}
1853+
1854+void JapanesePlugin::predict(const QString& surroundingLeft, const QString& preedit)
1855+{
1856+ Q_UNUSED(surroundingLeft)
1857+
1858+ m_nextWord = preedit;
1859+ if (!m_processingWord) {
1860+ m_processingWord = true;
1861+ Q_EMIT parsePredictionText(preedit);
1862+ }
1863+}
1864+
1865+void JapanesePlugin::wordCandidateSelected(QString word)
1866+{
1867+ Q_EMIT candidateSelected(word);
1868+}
1869+
1870+void JapanesePlugin::finishedProcessing(QString word, QStringList suggestions)
1871+{
1872+ Q_EMIT newPredictionSuggestions(word, suggestions);
1873+ if (word != m_nextWord) {
1874+ Q_EMIT parsePredictionText(m_nextWord);
1875+ } else {
1876+ m_processingWord = false;
1877+ }
1878+}
1879+
1880
1881=== added file 'plugins/ja/src/japaneseplugin.h'
1882--- plugins/ja/src/japaneseplugin.h 1970-01-01 00:00:00 +0000
1883+++ plugins/ja/src/japaneseplugin.h 2016-02-19 18:07:05 +0000
1884@@ -0,0 +1,43 @@
1885+#ifndef JAPANESEPLUGIN_H
1886+#define JAPANESEPLUGIN_H
1887+
1888+#include <QObject>
1889+#include <QThread>
1890+#include "languageplugininterface.h"
1891+#include "abstractlanguageplugin.h"
1892+
1893+#include "anthyadapter.h"
1894+
1895+class JapaneseLanguageFeatures;
1896+
1897+class JapanesePlugin : public AbstractLanguagePlugin
1898+{
1899+ Q_OBJECT
1900+ Q_INTERFACES(LanguagePluginInterface)
1901+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.JapanesePlugin" FILE "japaneseplugin.json")
1902+
1903+public:
1904+ explicit JapanesePlugin(QObject* parent = 0);
1905+ virtual ~JapanesePlugin();
1906+ virtual AbstractLanguageFeatures* languageFeature();
1907+
1908+ virtual void predict(const QString& surroundingLeft, const QString& preedit);
1909+ virtual void wordCandidateSelected(QString word);
1910+
1911+signals:
1912+ void newPredictionSuggestions(QString word, QStringList suggestions);
1913+ void parsePredictionText(QString preedit);
1914+ void candidateSelected(QString word);
1915+
1916+public slots:
1917+ void finishedProcessing(QString word, QStringList suggestions);
1918+
1919+private:
1920+ JapaneseLanguageFeatures* m_japaneseLanguageFeatures;
1921+ QThread *m_anthyThread;
1922+ AnthyAdapter *m_anthyAdapter;
1923+ QString m_nextWord;
1924+ bool m_processingWord;
1925+};
1926+
1927+#endif // JAPANESEPLUGIN_H
1928
1929=== added file 'plugins/ja/src/japaneseplugin.json'
1930--- plugins/ja/src/japaneseplugin.json 1970-01-01 00:00:00 +0000
1931+++ plugins/ja/src/japaneseplugin.json 2016-02-19 18:07:05 +0000
1932@@ -0,0 +1,7 @@
1933+{
1934+ "IID": "org.qt-project.Qt.Examples.JapanesePlugin",
1935+ "MetaData": {
1936+ },
1937+ "className": "JapanesePlugin",
1938+ "debug": true
1939+}
1940
1941=== added file 'plugins/ja/src/src.pro'
1942--- plugins/ja/src/src.pro 1970-01-01 00:00:00 +0000
1943+++ plugins/ja/src/src.pro 2016-02-19 18:07:05 +0000
1944@@ -0,0 +1,39 @@
1945+TOP_BUILDDIR = $$OUT_PWD/../../..
1946+TOP_SRCDIR = $$PWD/../../..
1947+
1948+include($${TOP_SRCDIR}/config.pri)
1949+
1950+TEMPLATE = lib
1951+CONFIG += plugin
1952+QT += widgets
1953+INCLUDEPATH += \
1954+ $${TOP_SRCDIR}/src/ \
1955+ $${TOP_SRCDIR}/src/lib/ \
1956+ $${TOP_SRCDIR}/src/lib/logic/
1957+
1958+HEADERS = \
1959+ japaneseplugin.h \
1960+ japaneselanguagefeatures.h \
1961+ anthyadapter.h \
1962+ $${TOP_SRCDIR}/src/lib/logic/abstractlanguageplugin.h
1963+
1964+SOURCES = \
1965+ japaneseplugin.cpp \
1966+ japaneselanguagefeatures.cpp \
1967+ anthyadapter.cpp \
1968+ $${TOP_SRCDIR}/src/lib/logic/abstractlanguageplugin.cpp
1969+
1970+TARGET = $$qtLibraryTarget(japlugin)
1971+
1972+EXAMPLE_FILES = japaneseplugin.json
1973+
1974+# generate database for presage:
1975+PLUGIN_INSTALL_PATH = $${UBUNTU_KEYBOARD_LIB_DIR}/ja/
1976+
1977+target.path = $$PLUGIN_INSTALL_PATH
1978+INSTALLS += target
1979+
1980+OTHER_FILES += \
1981+ jaglishplugin.json
1982+
1983+LIBS += -lpresage -lanthy -lanthydic
1984
1985=== added directory 'plugins/ja/tests'
1986=== modified file 'plugins/plugins.pro'
1987--- plugins/plugins.pro 2015-05-11 12:52:42 +0000
1988+++ plugins/plugins.pro 2016-02-19 18:07:05 +0000
1989@@ -21,6 +21,7 @@
1990 hu \
1991 is \
1992 it \
1993+ ja \
1994 nb \
1995 nl \
1996 pl \
1997
1998=== modified file 'qml/keys/languages.js'
1999--- qml/keys/languages.js 2016-01-18 13:19:13 +0000
2000+++ qml/keys/languages.js 2016-02-19 18:07:05 +0000
2001@@ -35,6 +35,7 @@
2002 if (languageId == "hu") return i18n.tr("Hungarian");
2003 if (languageId == "is") return i18n.tr("Icelandic");
2004 if (languageId == "it") return i18n.tr("Italian");
2005+ if (languageId == "ja") return i18n.tr("Japanese");
2006 if (languageId == "nl") return i18n.tr("Dutch");
2007 if (languageId == "nb") return i18n.tr("Norwegian");
2008 if (languageId == "pl") return i18n.tr("Polish");
2009
2010=== modified file 'src/lib/logic/abstractlanguagefeatures.h'
2011--- src/lib/logic/abstractlanguagefeatures.h 2014-12-08 14:26:19 +0000
2012+++ src/lib/logic/abstractlanguagefeatures.h 2016-02-19 18:07:05 +0000
2013@@ -54,6 +54,8 @@
2014 // can be disabled by implementing this method to return true.
2015 virtual bool ignoreSimilarity() const { return false; }
2016 virtual bool wordEngineAvailable() const { return false; }
2017+ virtual bool enablePreeditAtInsertion() const { return false; }
2018+ virtual bool restorePreedit() const { return true; }
2019
2020 Maliit::TextContentType contentType() const { return m_contentType; }
2021 void setContentType(Maliit::TextContentType contentType) { m_contentType = contentType; }
2022
2023=== modified file 'src/lib/logic/eventhandler.cpp'
2024--- src/lib/logic/eventhandler.cpp 2015-07-16 13:55:08 +0000
2025+++ src/lib/logic/eventhandler.cpp 2016-02-19 18:07:05 +0000
2026@@ -84,6 +84,8 @@
2027
2028 if (action == "return")
2029 key.setAction(Key::ActionReturn);
2030+ else if (action == "commit")
2031+ key.setAction(Key::ActionCommit);
2032 else if (action == "backspace")
2033 key.setAction(Key::ActionBackspace);
2034 else if (action == "space")
2035
2036=== modified file 'src/plugin/inputmethod.cpp'
2037--- src/plugin/inputmethod.cpp 2015-06-02 10:22:09 +0000
2038+++ src/plugin/inputmethod.cpp 2016-02-19 18:07:05 +0000
2039@@ -110,6 +110,10 @@
2040 connect(this, SIGNAL(keyboardStateChanged(QString)), &d->editor, SLOT(onKeyboardStateChanged(QString)));
2041 connect(d->m_geometry, SIGNAL(visibleRectChanged()), this, SLOT(onVisibleRectChanged()));
2042 connect(&d->m_settings, SIGNAL(disableHeightChanged(bool)), this, SLOT(onVisibleRectChanged()));
2043+
2044+ connect(&d->editor, SIGNAL(preeditChanged(QString)), this, SIGNAL(preeditChanged(QString)));
2045+ connect(&d->editor, SIGNAL(cursorPositionChanged(int)), this, SIGNAL(cursorPositionChanged(int)));
2046+
2047 d->registerAudioFeedbackSoundSetting();
2048 d->registerAudioFeedbackSetting();
2049 d->registerHapticFeedbackSetting();
2050@@ -643,6 +647,31 @@
2051 return d->currentPluginPath;
2052 }
2053
2054+const QString &InputMethod::preedit()
2055+{
2056+ Q_D(InputMethod);
2057+ d->preedit = d->editor.text()->preedit();
2058+ return d->preedit;
2059+}
2060+
2061+int InputMethod::cursorPosition() const
2062+{
2063+ Q_D(const InputMethod);
2064+ return d->editor.text()->cursorPosition();
2065+}
2066+
2067+void InputMethod::replacePreedit(const QString &preedit)
2068+{
2069+ Q_D(InputMethod);
2070+ d->editor.replacePreedit(preedit);
2071+}
2072+
2073+void InputMethod::setCursorPosition(const int pos)
2074+{
2075+ Q_D(InputMethod);
2076+ d->editor.setCursorPosition(pos);
2077+}
2078+
2079 bool InputMethod::languageIsSupported(const QString plugin) {
2080 Q_D(const InputMethod);
2081 foreach(QString pluginPath, d->pluginPaths) {
2082
2083=== modified file 'src/plugin/inputmethod.h'
2084--- src/plugin/inputmethod.h 2015-04-15 14:03:42 +0000
2085+++ src/plugin/inputmethod.h 2016-02-19 18:07:05 +0000
2086@@ -59,6 +59,8 @@
2087 Q_PROPERTY(QString keyboardState READ keyboardState WRITE setKeyboardState NOTIFY keyboardStateChanged)
2088 Q_PROPERTY(bool hasSelection READ hasSelection NOTIFY hasSelectionChanged)
2089 Q_PROPERTY(QString currentPluginPath READ currentPluginPath NOTIFY currentPluginPathChanged)
2090+ Q_PROPERTY(QString preedit READ preedit WRITE replacePreedit NOTIFY preeditChanged)
2091+ Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
2092
2093 Q_ENUMS(TextContentType)
2094
2095@@ -126,6 +128,11 @@
2096
2097 const QString currentPluginPath() const;
2098
2099+ const QString &preedit();
2100+ void replacePreedit(const QString &preedit);
2101+ int cursorPosition() const;
2102+ void setCursorPosition(const int pos);
2103+
2104 QObject* actionKeyOverride() const;
2105
2106 Q_SLOT void close();
2107@@ -154,6 +161,8 @@
2108 void hasSelectionChanged(bool hasSelection);
2109 void currentPluginPathChanged(QString currentPluginPath);
2110 void languagePluginChanged(QString pluginPath, QString languageId);
2111+ void preeditChanged(QString preedit);
2112+ void cursorPositionChanged(int cursor_position);
2113
2114 private:
2115 Q_SLOT void onAutoCorrectSettingChanged();
2116
2117=== modified file 'src/plugin/inputmethod_p.h'
2118--- src/plugin/inputmethod_p.h 2015-04-15 14:03:42 +0000
2119+++ src/plugin/inputmethod_p.h 2016-02-19 18:07:05 +0000
2120@@ -61,6 +61,8 @@
2121 QString keyboardState;
2122 bool hasSelection;
2123
2124+ QString preedit;
2125+
2126 KeyboardGeometry *m_geometry;
2127 KeyboardSettings m_settings;
2128 GreeterStatus *m_greeterStatus;
2129@@ -89,6 +91,7 @@
2130 , appsCurrentOrientation(qGuiApp->primaryScreen()->orientation())
2131 , keyboardState("CHARACTERS")
2132 , hasSelection(false)
2133+ , preedit("")
2134 , m_geometry(new KeyboardGeometry(q))
2135 , m_settings()
2136 , m_greeterStatus(new GreeterStatus())
2137
2138=== modified file 'src/view/abstracttexteditor.cpp'
2139--- src/view/abstracttexteditor.cpp 2015-07-16 13:55:08 +0000
2140+++ src/view/abstracttexteditor.cpp 2016-02-19 18:07:05 +0000
2141@@ -126,6 +126,14 @@
2142 //! \brief Emitted when preedit setting changes.
2143 //! \param enabled New setting.
2144
2145+//! \fn void AbstractTextEditor::preeditChanged(const QString &preedit)
2146+//! \brief Emitted when preedit string changes.
2147+//! \param enabled New string.
2148+
2149+//! \fn void AbstractTextEditor::cursorPositionChanged(int pos)
2150+//! \brief Emitted when preedit cusor position changes.
2151+//! \param enabled New position.
2152+
2153 //! \fn void AbstractTextEditor::wordCandidatesChanged(const WordCandidateList &word_candidates)
2154 //! \brief Emitted when new word candidates are generated.
2155 //! \param word_candidates New word candidates.
2156@@ -373,11 +381,13 @@
2157 const bool isSymbol = d->word_engine->languageFeature()->isSymbol(text);
2158 const bool replace_preedit = d->auto_correct_enabled && not d->text->primaryCandidate().isEmpty() &&
2159 not d->text->preedit().isEmpty() && isSeparator;
2160+ const bool enablePreeditAtInsertion = d->word_engine->languageFeature()->enablePreeditAtInsertion();
2161
2162 d->previous_preedit = "";
2163
2164 if (d->preedit_enabled) {
2165- if (d->text->surroundingRight().left(1).contains(QRegExp("[\\w]")) || email_detected) {
2166+ if (!enablePreeditAtInsertion &&
2167+ (d->text->surroundingRight().left(1).contains(QRegExp("[\\w]")) || email_detected)) {
2168 // We're editing in the middle of a word or entering an email address, so just insert characters directly
2169 d->text->appendToPreedit(text);
2170 commitPreedit();
2171@@ -429,6 +439,9 @@
2172 // standard input (like certain separators, e.g. '.' in western languages) can also trigger autoCaps
2173 Q_EMIT autoCapsActivated();
2174 }
2175+
2176+ Q_EMIT preeditChanged(d->text->preedit());
2177+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2178 } break;
2179
2180 case Key::ActionBackspace: {
2181@@ -505,6 +518,9 @@
2182 d->text->appendToPreedit(space);
2183 commitPreedit();
2184
2185+ Q_EMIT preeditChanged(d->text->preedit());
2186+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2187+
2188 if (auto_caps_activated && d->auto_caps_enabled) {
2189 Q_EMIT autoCapsActivated();
2190 }
2191@@ -515,6 +531,13 @@
2192 keyText = QString("\r");
2193 } break;
2194
2195+ case Key::ActionCommit: {
2196+ commitPreedit();
2197+
2198+ Q_EMIT preeditChanged(d->text->preedit());
2199+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2200+ } break;
2201+
2202 case Key::ActionClose:
2203 Q_EMIT keyboardClosed();
2204 break;
2205@@ -561,6 +584,9 @@
2206 if (event_key != Qt::Key_unknown) {
2207 commitPreedit();
2208 sendKeyPressAndReleaseEvents(event_key, Qt::NoModifier, keyText);
2209+
2210+ Q_EMIT preeditChanged(d->text->preedit());
2211+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2212 }
2213 }
2214
2215@@ -614,6 +640,9 @@
2216 // before sending preedit:
2217 d->word_engine->computeCandidates(d->text.data());
2218 sendPreeditString(d->text->preedit(), d->text->preeditFace());
2219+
2220+ Q_EMIT preeditChanged(d->text->preedit());
2221+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2222 }
2223
2224 void AbstractTextEditor::replaceTextWithPreedit(const QString &replacement, int start, int len, int pos)
2225@@ -629,6 +658,9 @@
2226 Replacement word_r(start, len, pos);
2227 sendPreeditString(d->text->preedit(), d->text->preeditFace(),
2228 word_r);
2229+
2230+ Q_EMIT preeditChanged(d->text->preedit());
2231+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2232 }
2233
2234 //! \brief Replaces current preedit with given replacement and then
2235@@ -662,6 +694,9 @@
2236 Q_EMIT autoCapsDeactivated();
2237 }
2238 }
2239+
2240+ Q_EMIT preeditChanged(d->text->preedit());
2241+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2242 }
2243
2244 //! \brief Clears preedit.
2245@@ -702,6 +737,27 @@
2246 }
2247 }
2248
2249+//! \brief Set cursor position of preedit.
2250+void AbstractTextEditor::setCursorPosition(int pos)
2251+{
2252+ Q_D(AbstractTextEditor);
2253+
2254+ if (not d->valid()) {
2255+ return;
2256+ }
2257+
2258+ if (pos == d->text->cursorPosition()) {
2259+ return;
2260+ }
2261+
2262+ d->text->setCursorPosition(pos);
2263+
2264+ sendPreeditString(d->text->preedit(), d->text->preeditFace(),
2265+ Replacement(d->text->cursorPosition()));
2266+ Q_EMIT preeditChanged(d->text->preedit());
2267+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2268+}
2269+
2270 //! \brief Returns whether auto-correct functionality is enabled.
2271 //! \sa autoCorrectEnabled
2272 bool AbstractTextEditor::isAutoCorrectEnabled() const
2273@@ -906,7 +962,10 @@
2274 // Clear previous word candidates
2275 Q_EMIT wordCandidatesChanged(WordCandidateList());
2276 sendPreeditString(d->text->preedit(), d->text->preeditFace(),
2277- Replacement());
2278+ Replacement(d->text->cursorPosition()));
2279+
2280+ Q_EMIT preeditChanged(d->text->preedit());
2281+ Q_EMIT cursorPositionChanged(d->text->cursorPosition());
2282
2283 if (d->text->preedit().isEmpty()) {
2284 d->word_engine->clearCandidates();
2285@@ -983,6 +1042,10 @@
2286 return;
2287 }
2288
2289+ if(!d->word_engine->languageFeature()->restorePreedit()) {
2290+ return;
2291+ }
2292+
2293 int currentOffset = text()->surroundingOffset();
2294 if(currentOffset > 1 && currentOffset <= text()->surrounding().size()) {
2295 QString lastChar;
2296@@ -1023,10 +1086,8 @@
2297 }
2298 d->previous_preedit = "";
2299 }
2300-
2301 replaceTextWithPreedit(recreatedPreedit, 0, 0, recreatedPreedit.size());
2302 }
2303-
2304 }
2305
2306 d->word_engine->computeCandidates(d->text.data());
2307
2308=== modified file 'src/view/abstracttexteditor.h'
2309--- src/view/abstracttexteditor.h 2015-03-16 13:06:42 +0000
2310+++ src/view/abstracttexteditor.h 2016-02-19 18:07:05 +0000
2311@@ -129,6 +129,10 @@
2312 Q_SLOT void setPreeditEnabled(bool enabled);
2313 Q_SIGNAL void preeditEnabledChanged(bool enabled);
2314
2315+ Q_SIGNAL void preeditChanged(const QString &preedit);
2316+ Q_SLOT void setCursorPosition(int pos);
2317+ Q_SIGNAL void cursorPositionChanged(int pos);
2318+
2319 bool isAutoCorrectEnabled() const;
2320 Q_SLOT void setAutoCorrectEnabled(bool enabled);
2321 Q_SIGNAL void autoCorrectEnabledChanged(bool enabled);

Subscribers

People subscribed via source and target branches