Convert characters offset to bytes offset.
[ibus.git] / engine / anthy / engine.py
blobb23ad90772c3f7817c0be32b0ca9cf50f6e5ed59
1 #!/usr/bin/env python
2 import gobject
3 import gtk
4 import pango
5 import dbus
6 import ibus
7 import anthy
8 from tables import *
9 from ibus import keysyms
10 from ibus import interface
12 class Engine (interface.IEngine):
13 def __init__ (self, dbusconn, object_path):
14 interface.IEngine.__init__ (self, dbusconn, object_path)
15 self._dbusconn = dbusconn
17 # create anthy context
18 self._context = anthy.anthy_context ()
19 self._context._set_encoding (2)
21 self._lookup_table = ibus.LookupTable ()
22 self._prop_list = ibus.PropList ()
24 # use reset to init values
25 self._reset ()
27 # reset values of engine
28 def _reset (self):
29 self._input_chars = u""
30 self._convert_chars = u""
31 self._cursor_pos = 0
32 self._need_update = False
33 self._convert_begined = False
34 self._segments = []
35 self._lookup_table.clean ()
36 self._lookup_table_visible = False
38 # begine convert
39 def _begin_convert (self):
40 if self._convert_begined:
41 return
42 self._convert_begined = True
44 self._context.set_string (self._input_chars.encode ("utf-8"))
45 conv_stat = anthy.anthy_conv_stat ()
46 self._context.get_stat (conv_stat)
48 for i in xrange (0, conv_stat.nr_segment):
49 buf = " " * 100
50 l = self._context.get_segment (i, 0, buf, 100)
51 text = unicode (buf[:l], "utf-8")
52 self._segments.append ((0, text))
54 self._cursor_pos = 0
55 self._fill_lookup_table ()
56 self._lookup_table_visible = False
58 def _fill_lookup_table (self):
59 # get segment stat
60 seg_stat = anthy.anthy_segment_stat ()
61 self._context.get_segment_stat (self._cursor_pos, seg_stat)
63 # fill lookup_table
64 self._lookup_table.clean ()
65 for i in xrange (0, seg_stat.nr_candidate):
66 buf = " " * 100
67 l = self._context.get_segment (self._cursor_pos, i, buf, 100)
68 candidate = unicode (buf[:l], "utf-8")
69 self._lookup_table.append_candidate (candidate)
72 def _invalidate (self):
73 if self._need_update:
74 return
75 self._need_update = True
76 gobject.idle_add (self._update, priority = gobject.PRIORITY_LOW)
78 def _page_up (self):
79 # only process cursor down in convert mode
80 if not self._convert_begined:
81 return False
83 if not self._lookup_table.page_up ():
84 return False
86 candidate = self._lookup_table.get_current_candidate ()[0]
87 index = self._lookup_table.get_cursor_pos ()
88 self._segments[self._cursor_pos] = index, candidate
89 self._invalidate ()
90 return True
92 def _page_down (self):
93 # only process cursor down in convert mode
94 if not self._convert_begined:
95 return False
97 if not self._lookup_table.page_down ():
98 return False
100 candidate = self._lookup_table.get_current_candidate ()[0]
101 index = self._lookup_table.get_cursor_pos ()
102 self._segments[self._cursor_pos] = index, candidate
103 self._invalidate ()
104 return True
106 def _cursor_up (self):
107 # only process cursor down in convert mode
108 if not self._convert_begined:
109 return False
111 if not self._lookup_table.cursor_up ():
112 return False
114 candidate = self._lookup_table.get_current_candidate ()[0]
115 index = self._lookup_table.get_cursor_pos ()
116 self._segments[self._cursor_pos] = index, candidate
117 self._invalidate ()
118 return True
120 def _cursor_down (self):
121 # only process cursor down in convert mode
122 if not self._convert_begined:
123 return False
125 if not self._lookup_table.cursor_down ():
126 return False
128 candidate = self._lookup_table.get_current_candidate ()[0]
129 index = self._lookup_table.get_cursor_pos ()
130 self._segments[self._cursor_pos] = index, candidate
131 self._invalidate ()
132 return True
134 def _commit_string (self, text):
135 self._reset ()
136 self.CommitString (text)
137 self._update ()
139 def _update_input_chars (self):
140 begin, end = max (self._cursor_pos - 4, 0), self._cursor_pos
142 for i in range (begin, end):
143 text = self._input_chars[i:end]
144 romja = romaji_typing_rule.get (text, None)
145 if romja != None:
146 self._input_chars = u"".join ((self._input_chars[:i], romja, self._input_chars[end:]))
147 self._cursor_pos -= len(text)
148 self._cursor_pos += len(romja)
150 attrs = ibus.AttrList ()
151 attrs.append (ibus.AttributeUnderline (pango.UNDERLINE_SINGLE, 0, len (self._input_chars.encode ("utf-8"))))
153 self.UpdatePreedit (dbus.String (self._input_chars),
154 attrs.to_dbus_value (),
155 dbus.Int32 (self._cursor_pos),
156 len (self._input_chars) > 0)
157 self.UpdateAuxString (u"", ibus.AttrList ().to_dbus_value (), False)
158 self.UpdateLookupTable (self._lookup_table.to_dbus_value (), self._lookup_table_visible)
160 def _update_convert_chars (self):
161 self._convert_chars = u""
162 buf = " " * 100
163 pos = 0
164 i = 0
165 for seg_index, text in self._segments:
166 self._convert_chars += text
167 if i <= self._cursor_pos:
168 pos += len (text)
169 i += 1
171 attrs = ibus.AttrList ()
172 attrs.append (ibus.AttributeUnderline (pango.UNDERLINE_SINGLE, 0, len (self._convert_chars.encode ("utf-8"))))
174 self.UpdatePreedit (dbus.String (self._convert_chars),
175 attrs.to_dbus_value (),
176 dbus.Int32 (pos),
177 True)
178 aux_string = u"( %d / %d )" % (self._lookup_table.get_cursor_pos () + 1, self._lookup_table.get_number_of_candidates())
179 self.UpdateAuxString (aux_string, ibus.AttrList ().to_dbus_value (), self._lookup_table_visible)
180 self.UpdateLookupTable (self._lookup_table.to_dbus_value (), self._lookup_table_visible)
182 def _update (self):
183 self._need_update = False
184 if self._convert_begined == False:
185 self._update_input_chars ()
186 else:
187 self._update_convert_chars ()
189 def _on_key_return (self):
190 if not self._input_chars:
191 return False
192 if self._convert_begined == False:
193 self._commit_string (self._input_chars)
194 else:
195 i = 0
196 for seg_index, text in self._segments:
197 self._context.commit_segment (i, seg_index)
198 self._commit_string (self._convert_chars)
199 return True
201 def _on_key_escape (self):
202 if not self._input_chars:
203 return False
204 self._reset ()
205 self._invalidate ()
206 return True
208 def _on_key_back_space (self):
209 if not self._input_chars:
210 return False
212 if self._convert_begined:
213 self._convert_begined = False
214 self._cursor_pos = len (self._input_chars)
215 self._lookup_table.clean ()
216 self._lookup_table_visible = False
217 elif self._cursor_pos > 0:
218 self._input_chars = self._input_chars[:self._cursor_pos - 1] + self._input_chars [self._cursor_pos:]
219 self._cursor_pos -= 1
221 self._invalidate ()
222 return True
224 def _on_key_delete (self):
225 if not self._input_chars:
226 return False
228 if self._convert_begined:
229 self._convert_begined = False
230 self._cursor_pos = len (self._input_chars)
231 self._lookup_table.clean ()
232 self._lookup_table_visible = False
233 elif self._cursor_pos < len (self._input_chars):
234 self._input_chars = self._input_chars[:self._cursor_pos] + self._input_chars [self._cursor_pos + 1:]
236 self._invalidate ()
237 return True
239 def _on_key_space (self):
240 if not self._input_chars:
241 return False
242 if self._convert_begined == False:
243 self._begin_convert ()
244 self._invalidate ()
245 else:
246 self._lookup_table_visible = True
247 self._cursor_down ()
248 return True
250 def _on_key_up (self):
251 if not self._input_chars:
252 return False
253 self._lookup_table_visible = True
254 self._cursor_up ()
255 return True
257 def _on_key_down (self):
258 if not self._input_chars:
259 return False
260 self._lookup_table_visible = True
261 self._cursor_down ()
262 return True
264 def _on_key_page_up (self):
265 if not self._input_chars:
266 return False
267 if self._lookup_table_visible == True:
268 self._page_up ()
269 return True
271 def _on_key_page_down (self):
272 if not self._input_chars:
273 return False
274 if self._lookup_table_visible == True:
275 self._page_down ()
276 return True
278 def _on_key_left (self):
279 if not self._input_chars:
280 return False
281 if self._cursor_pos == 0:
282 return True
283 self._cursor_pos -= 1
284 self._lookup_table_visible = False
285 self._fill_lookup_table ()
286 self._invalidate ()
287 return True
289 def _on_key_right (self):
290 if not self._input_chars:
291 return False
293 if self._convert_begined:
294 max_pos = len (self._segments) - 1
295 else:
296 max_pos = len (self._input_chars)
297 if self._cursor_pos == max_pos:
298 return True
299 self._cursor_pos += 1
300 self._lookup_table_visible = False
301 self._fill_lookup_table ()
302 self._invalidate ()
304 return True
306 def _on_key_number (self, index):
307 if not self._input_chars:
308 return False
310 if self._convert_begined and self._lookup_table_visible:
311 candidates = self._lookup_table.get_canidates_in_current_page ()
312 if self._lookup_table.set_cursor_pos_in_current_page (index):
313 index = self._lookup_table.get_cursor_pos ()
314 candidate = self._lookup_table.get_current_candidate ()[0]
315 self._segments[self._cursor_pos] = index, candidate
316 self._lookup_table_visible = False
317 self._on_key_right ()
318 self._invalidate ()
319 return True
322 def _on_key_common (self, keyval):
323 self._input_chars += unichr (keyval)
324 self._cursor_pos += 1
325 self._invalidate ()
326 return True
328 def _process_key_event (self, keyval, is_press, state):
329 # ignore key release events
330 if not is_press:
331 return False
333 if keyval == keysyms.Return:
334 return self._on_key_return ()
335 elif keyval == keysyms.Escape:
336 return self._on_key_escape ()
337 elif keyval == keysyms.BackSpace:
338 return self._on_key_back_space ()
339 elif keyval == keysyms.Delete or keyval == keysyms.KP_Delete:
340 return self._on_key_delete ()
341 elif keyval == keysyms.space:
342 return self._on_key_space ()
343 elif keyval >= keysyms._1 and keyval <= keysyms._9:
344 index = keyval - keysyms._1
345 return self._on_key_number (index)
346 elif keyval == keysyms.Page_Up or keyval == keysyms.KP_Page_Up:
347 return self._on_key_page_up ()
348 elif keyval == keysyms.Page_Down or keyval == keysyms.KP_Page_Down:
349 return self._on_key_page_down ()
350 elif keyval == keysyms.Up:
351 return self._on_key_up ()
352 elif keyval == keysyms.Down:
353 return self._on_key_down ()
354 elif keyval == keysyms.Left:
355 return self._on_key_left ()
356 elif keyval == keysyms.Right:
357 return self._on_key_right ()
358 elif keyval in xrange (keysyms.a, keysyms.z + 1) or \
359 keyval in xrange (keysyms.A, keysyms.Z + 1):
360 return self._on_key_common (keyval)
361 else:
362 return True
364 return False
366 # methods for dbus rpc
367 def ProcessKeyEvent (self, keyval, is_press, state):
368 try:
369 return self._process_key_event (keyval, is_press, state)
370 except Exception, e:
371 print e
372 return False
374 def FocusIn (self):
375 self.RegisterProperties (self._prop_list.to_dbus_value ())
376 print "FocusIn"
378 def FocusOut (self):
379 print "FocusOut"
381 def SetCursorLocation (self, x, y, w, h):
382 pass
384 def Reset (self):
385 print "Reset"
387 def PageUp (self):
388 self._page_up ()
390 def PageDown (self):
391 self._page_down ()
393 def CursorUp (self):
394 self._cursor_up ()
396 def CursorDown (self):
397 self._cursor_down ()
399 def SetEnable (self, enable):
400 self._enable = enable
401 if self._enable:
402 self.RegisterProperties (self._prop_list.to_dbus_value ())
404 def PropertyActivate (self, prop_name):
405 print "PropertyActivate (%s)" % prop_name
407 def Destroy (self):
408 print "Destroy"