文件操作 - table.py
返回文件管理
返回主菜单
删除本文件
文件: /usr/share/ibus-table/engine/table.py
编辑文件内容
# -*- coding: utf-8 -*- # vim:et sts=4 sw=4 # # ibus-table - The Tables engine for IBus # # Copyright (c) 2008-2009 Yu Yuwei <acevery@gmail.com> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # $Id: $ # __all__ = ( "tabengine", ) import os import string from gi.repository import IBus from gi.repository import GLib from curses import ascii #import tabsqlitedb import tabdict import re patt_edit = re.compile (r'(.*)###(.*)###(.*)') patt_uncommit = re.compile (r'(.*)@@@(.*)') from gettext import dgettext _ = lambda a : dgettext ("ibus-table", a) N_ = lambda a : a def variant_to_value(variant): if type(variant) != GLib.Variant: return variant type_string = variant.get_type_string() if type_string == 's': return variant.get_string() elif type_string == 'i': return variant.get_int32() elif type_string == 'b': return variant.get_boolean() elif type_string == 'as': # In the latest pygobject3 3.3.4 or later, g_variant_dup_strv # returns the allocated strv but in the previous release, # it returned the tuple of (strv, length) if type(GLib.Variant.new_strv([]).dup_strv()) == tuple: return variant.dup_strv()[0] else: return variant.dup_strv() else: print 'error: unknown variant type:', type_string return variant def argb(a, r, g, b): return ((a & 0xff)<<24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff) def rgb(r, g, b): return argb(255, r, g, b) __half_full_table = [ (0x0020, 0x3000, 1), (0x0021, 0xFF01, 0x5E), (0x00A2, 0xFFE0, 2), (0x00A5, 0xFFE5, 1), (0x00A6, 0xFFE4, 1), (0x00AC, 0xFFE2, 1), (0x00AF, 0xFFE3, 1), (0x20A9, 0xFFE6, 1), (0xFF61, 0x3002, 1), (0xFF62, 0x300C, 2), (0xFF64, 0x3001, 1), (0xFF65, 0x30FB, 1), (0xFF66, 0x30F2, 1), (0xFF67, 0x30A1, 1), (0xFF68, 0x30A3, 1), (0xFF69, 0x30A5, 1), (0xFF6A, 0x30A7, 1), (0xFF6B, 0x30A9, 1), (0xFF6C, 0x30E3, 1), (0xFF6D, 0x30E5, 1), (0xFF6E, 0x30E7, 1), (0xFF6F, 0x30C3, 1), (0xFF70, 0x30FC, 1), (0xFF71, 0x30A2, 1), (0xFF72, 0x30A4, 1), (0xFF73, 0x30A6, 1), (0xFF74, 0x30A8, 1), (0xFF75, 0x30AA, 2), (0xFF77, 0x30AD, 1), (0xFF78, 0x30AF, 1), (0xFF79, 0x30B1, 1), (0xFF7A, 0x30B3, 1), (0xFF7B, 0x30B5, 1), (0xFF7C, 0x30B7, 1), (0xFF7D, 0x30B9, 1), (0xFF7E, 0x30BB, 1), (0xFF7F, 0x30BD, 1), (0xFF80, 0x30BF, 1), (0xFF81, 0x30C1, 1), (0xFF82, 0x30C4, 1), (0xFF83, 0x30C6, 1), (0xFF84, 0x30C8, 1), (0xFF85, 0x30CA, 6), (0xFF8B, 0x30D2, 1), (0xFF8C, 0x30D5, 1), (0xFF8D, 0x30D8, 1), (0xFF8E, 0x30DB, 1), (0xFF8F, 0x30DE, 5), (0xFF94, 0x30E4, 1), (0xFF95, 0x30E6, 1), (0xFF96, 0x30E8, 6), (0xFF9C, 0x30EF, 1), (0xFF9D, 0x30F3, 1), (0xFFA0, 0x3164, 1), (0xFFA1, 0x3131, 30), (0xFFC2, 0x314F, 6), (0xFFCA, 0x3155, 6), (0xFFD2, 0x315B, 9), (0xFFE9, 0x2190, 4), (0xFFED, 0x25A0, 1), (0xFFEE, 0x25CB, 1)] def unichar_half_to_full (c): code = ord (c) for half, full, size in __half_full_table: if code >= half and code < half + size: return unichr (full + code - half) return c def unichar_full_to_half (c): code = ord (c) for half, full, size in __half_full_table: if code >= full and code < full + size: return unichr (half + code - full) return c class KeyEvent: def __init__(self, keyval, is_press, state): self.code = keyval self.mask = state if not is_press: self.mask |= IBus.ModifierType.RELEASE_MASK def __str__(self): return "%s 0x%08x" % (IBus.keyval_name(self.code), self.mask) class editor(object): '''Hold user inputs chars and preedit string''' def __init__ (self, config, phrase_table_index,valid_input_chars, max_key_length, database, parser = tabdict.parse, deparser = tabdict.deparse, max_length = 64): self.db = database self._config = config self._name = self.db.get_ime_property('name') self._config_section = "engine/Table/%s" % self._name.replace(' ','_') self._pt = phrase_table_index self._parser = parser self._deparser = deparser self._max_key_len = int(max_key_length) self._max_length = max_length self._valid_input_chars = valid_input_chars # # below vals will be reset in self.clear() # # we hold this: [str,str,...] # self._chars: hold user input in table mode (valid,invalid,prevalid) self._chars = [[],[],[]] #self._t_chars: hold total input for table mode for input check self._t_chars = [] # self._u_chars: hold user input but not manual comitted chars self._u_chars = [] # self._tabkey_list: hold tab_key objects transform from user input chars self._tabkey_list = [] # self._strings: hold preedit strings self._strings = [] # self._cursor: the caret position in preedit phrases self._cursor = [0,0] # self._candidates: hold candidates selected from database [[now],[pre]] self._candidates = [[],[]] # __orientation: lookup table orientation __orientation = variant_to_value(self._config.get_value( self._config_section, "LookupTableOrientation")) if __orientation == None: __orientation = self.db.get_orientation() # __page_size: lookup table page size # this is computed from the select_keys, so should be done after it __page_size = self.db.get_page_size() # self._lookup_table: lookup table self._lookup_table = IBus.LookupTable.new( page_size=__page_size, cursor_pos=0, cursor_visible=True, round=True) self._lookup_table.set_orientation (__orientation) # self._select_keys: a list of chars for select keys self.init_select_keys() # self._py_mode: whether in pinyin mode self._py_mode = False # self._zi: the last Zi commit to preedit self._zi = u'' # self._caret: caret position in lookup_table self._caret = 0 # self._onechar: whether we only select single character self._onechar = variant_to_value(self._config.get_value( self._config_section, "OneChar")) if self._onechar == None: self_onechar = False # self._chinese_mode: the candidate filter mode, # 0 means to show simplified Chinese only # 1 means to show traditional Chinese only # 2 means to show all characters but show simplified Chinese first # 3 means to show all characters but show traditional Chinese first # 4 means to show all characters # we use LC_CTYPE or LANG to determine which one to use self._chinese_mode = variant_to_value(self._config.get_value( self._config_section, "ChineseMode")) if self._chinese_mode == None: self._chinese_mode = self.get_chinese_mode() self._auto_select = variant_to_value(self._config.get_value( self._config_section, "AutoSelect")) if self._auto_select == None: if self.db.get_ime_property('auto_select') != None: self._auto_select = self.db.get_ime_property('auto_select').lower() == u'true' else: self._auto_select = False def init_select_keys(self): # __select_keys: lookup table select keys/labels __select_keys = variant_to_value(self._config.get_value( self._config_section, "LookupTableSelectKeys")) if __select_keys == None: __select_keys = self.db.get_select_keys() if __select_keys: self.set_select_keys(__select_keys) def set_select_keys(self, astring): """astring: select keys setting. e.g. 1,2,3,4,5,6,7,8,9""" self._select_keys = [x.strip() for x in astring.split(",")] for x in self._select_keys: self._lookup_table.append_label(IBus.Text.new_from_string("{}.".format(x))) def get_select_keys(self): """@return: a list of chars as select keys: ["1", "2", ...]""" return self._select_keys def get_chinese_mode (self): '''Use db value or LC_CTYPE in your box to determine the _chinese_mode''' # use db value, if applicable __db_chinese_mode = self.db.get_chinese_mode() if __db_chinese_mode >= 0: return __db_chinese_mode # otherwise try: if os.environ.has_key('LC_ALL'): __lc = os.environ['LC_ALL'].split('.')[0].lower() elif os.environ.has_key('LC_CTYPE'): __lc = os.environ['LC_CTYPE'].split('.')[0].lower() else: __lc = os.environ['LANG'].split('.')[0].lower() if __lc.find('_cn') != -1: return 0 # hk and tw is should use tc as default elif __lc.find('_hk') != -1 or __lc.find('_tw') != -1\ or __lc.find('_mo') != -1: return 1 else: if self.db._is_chinese: # if IME declare as Chinese IME return 0 else: return -1 except: return -1 def change_chinese_mode (self): if self._chinese_mode != -1: self._chinese_mode = (self._chinese_mode +1 ) % 5 self._config.set_value ( self._config_section, "ChineseMode", GLib.Variant.new_int32(self._chinese_mode)) def clear (self): '''Remove data holded''' self.over_input () self._t_chars = [] self._strings = [] self._cursor = [0,0] self._py_mode = False self._zi = u'' self.update_candidates def is_empty (self): return len(self._t_chars) == 0 def clear_input (self): ''' Remove input characters held for Table mode, ''' self._chars = [[],[],[]] self._tabkey_list = [] self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) self._candidates = [[],[]] def over_input (self): ''' Remove input characters held for Table mode, ''' self.clear_input () self._u_chars = [] def set_parser (self, parser): '''change input parser''' self.clear () self._parser = parser def add_input (self,c): '''add input character''' if len (self._t_chars) == self._max_length: return True self._zi = u'' if self._cursor[1]: self.split_phrase() if (len (self._chars[0]) == self._max_key_len and (not self._py_mode)) or ( len (self._chars[0]) == 7 and self._py_mode ) : self.auto_commit_to_preedit() res = self.add_input (c) return res elif self._chars[1]: self._chars[1].append (c) else: if (not self._py_mode and ( c in self._valid_input_chars)) or\ (self._py_mode and (c in u'abcdefghijklmnopqrstuvwxyz!@#$%')): try: self._tabkey_list += self._parser (c) self._chars[0].append (c) except: self._chars[1].append (c) else: self._chars[1].append (c) self._t_chars.append(c) res = self.update_candidates () return res def pop_input (self): '''remove and display last input char held''' _c ='' if self._chars[1]: _c = self._chars[1].pop () elif self._chars[0]: _c = self._chars[0].pop () self._tabkey_list.pop() if (not self._chars[0]) and self._u_chars: self._chars[0] = self._u_chars.pop() self._chars[1] = self._chars[1][:-1] self._tabkey_list = self._parser (self._chars[0]) self._strings.pop (self._cursor[0] - 1 ) self._cursor[0] -= 1 self._t_chars.pop() self.update_candidates () return _c def get_input_chars (self): '''get characters held, valid and invalid''' return self._chars[0] + self._chars[1] def get_input_chars_string (self): '''Get valid input char string''' return u''.join(map(str,self._t_chars)) def get_all_input_strings (self): '''Get all uncommit input characters, used in English mode or direct commit''' return u''.join( map(u''.join, self._u_chars + [self._chars[0]] \ + [self._chars[1]]) ) def get_index(self,key): '''Get the index of key in database table''' return self._pt.index(key) def split_phrase (self): '''Splite current phrase into two phrase''' _head = u'' _end = u'' try: _head = self._strings[self._cursor[0]][:self._cursor[1]] _end = self._strings[self._cursor[0]][self._cursor[1]:] self._strings.pop(self._cursor[0]) self._strings.insert(self._cursor[0],_head) self._strings.insert(self._cursor[0]+1,_end) self._cursor[0] +=1 self._cursor[1] = 0 except: pass def remove_before_string (self): '''Remove string before cursor''' if self._cursor[1] != 0: self.split_phrase() if self._cursor[0] > 0: self._strings.pop(self._cursor[0]-1) self._cursor[0] -= 1 else: pass # if we remove all characters in preedit string, we need to clear the self._t_chars if self._cursor == [0,0]: self._t_chars =[] def remove_after_string (self): '''Remove string after cursor''' if self._cursor[1] != 0: self.split_phrase() if self._cursor[0] >= len (self._strings): pass else: self._strings.pop(self._cursor[0]) def remove_before_char (self): '''Remove character before cursor''' if self._cursor[1] > 0: _str = self._strings[ self._cursor[0] ] self._strings[ self._cursor[0] ] = _str[ : self._cursor[1]-1] + _str[ self._cursor[1] :] self._cursor[1] -= 1 else: if self._cursor[0] == 0: pass else: if len ( self._strings[self._cursor[0] - 1] ) == 1: self.remove_before_string() else: self._strings[self._cursor[0] - 1] = self._strings[self._cursor[0] - 1][:-1] # if we remove all characters in preedit string, we need to clear the self._t_chars if self._cursor == [0,0] and not self._strings: self._t_chars =[] def remove_after_char (self): '''Remove character after cursor''' if self._cursor[1] == 0: if self._cursor[0] == len ( self._strings): pass else: if len( self._strings[ self._cursor[0] ]) == 1: self.remove_after_string () else: self._strings[ self._cursor[0] ] = self._strings[ self._cursor[0] ][1:] else: if ( self._cursor[1] + 1 ) == len( self._strings[ self._cursor[0] ] ) : self.split_phrase () self.remove_after_string () else: string = self._strings[ self._cursor[0] ] self._strings[ self._cursor[0] ] = string[:self._cursor[1]] + string[ self._cursor[1] + 1 : ] def get_invalid_input_chars (self): '''get invalid characters held''' return self._chars[1] def get_invalid_input_string (self): '''get invalid characters in string form''' return u''.join (self._chars[1]) def get_preedit_strings (self): '''Get preedit strings''' if self._candidates[0]: if self._py_mode: _p_index = 8 else: _p_index = self.get_index ('phrase') _candi = u'###' + self._candidates[0][ int (self._lookup_table.get_cursor_pos() ) ][ _p_index ] + u'###' else: input_chars = self.get_input_chars () if input_chars: _candi = u''.join( ['###'] + map( str, input_chars) + ['###'] ) else: _candi = u'' if self._strings: res = u'' _cursor = self._cursor[0] _luc = len (self._u_chars) if _luc: _candi = _candi == u'' and u'######' or _candi res =u''.join( self._strings[ : _cursor - _luc] +[u'@@@'] + self._strings[_cursor - _luc : _cursor ] + [ _candi ] + self._strings[ _cursor : ]) else: res = u''.join( self._strings[ : _cursor ] + [ _candi ] + self._strings[ _cursor : ]) return res else: return _candi def add_caret (self, addstr): '''add length to caret position''' self._caret += len(addstr) def get_caret (self): '''Get caret position in preedit strings''' self._caret = 0 if self._cursor[0] and self._strings: map (self.add_caret,self._strings[:self._cursor[0]]) self._caret += self._cursor[1] if self._candidates[0]: if self._py_mode: _p_index = 8 else: _p_index = self.get_index ('phrase') _candi =self._candidates[0][ int (self._lookup_table.get_cursor_pos() ) ][ _p_index ] else: _candi = u''.join( map( str,self.get_input_chars()) ) self._caret += len( _candi ) return self._caret def arrow_left (self): '''Process Arrow Left Key Event. Update cursor data when move caret left''' if self.get_preedit_strings (): if not( self.get_input_chars () or self._u_chars ): if self._cursor[1] > 0: self._cursor[1] -= 1 else: if self._cursor[0] > 0: self._cursor[1] = len (self._strings[self._cursor[0]-1]) - 1 self._cursor[0] -= 1 else: self._cursor[0] = len(self._strings) self._cursor[1] = 0 self.update_candidates () return True else: return False def arrow_right (self): '''Process Arrow Right Key Event. Update cursor data when move caret right''' if self.get_preedit_strings (): if not( self.get_input_chars () or self._u_chars ): if self._cursor[1] == 0: if self._cursor[0] == len (self._strings): self._cursor[0] = 0 else: self._cursor[1] += 1 else: self._cursor[1] += 1 if self._cursor[1] == len(self._strings[ self._cursor[0] ]): self._cursor[0] += 1 self._cursor[1] = 0 self.update_candidates () return True else: return False def control_arrow_left (self): '''Process Control + Arrow Left Key Event. Update cursor data when move caret to string left''' if self.get_preedit_strings (): if not( self.get_input_chars () or self._u_chars ): if self._cursor[1] == 0: if self._cursor[0] == 0: self._cursor[0] = len (self._strings) - 1 else: self._cursor[0] -= 1 else: self._cursor[1] = 0 self.update_candidates () return True else: return False def control_arrow_right (self): '''Process Control + Arrow Right Key Event. Update cursor data when move caret to string right''' if self.get_preedit_strings (): if not( self.get_input_chars () or self._u_chars ): if self._cursor[1] == 0: if self._cursor[0] == len (self._strings): self._cursor[0] = 1 else: self._cursor[0] += 1 else: self._cursor[0] += 1 self._cursor[1] = 0 self.update_candidates () return True else: return False def ap_candidate (self, candi): '''append candidate to lookup_table''' if not self._py_mode: _p_index = self.get_index('phrase') _fkey = self.get_index('m0') else: _p_index = 8 _fkey = 1 if self.db._is_chinese: _tbks = u''.join( map(self._deparser , candi[_fkey + len(self._tabkey_list) : _p_index-1 ] ) ) if self._py_mode: # restore tune symbol _tbks = _tbks.replace('!','↑1').replace('@','↑2').replace('#','↑3').replace('$','↑4').replace('%','↑5') else: _tbks = u''.join( map(self._deparser , candi[_fkey + len(self._tabkey_list) : _p_index ] ) ) _phrase = candi[_p_index] # further color implementation needed :) # here -2 is the pos of num, -1 is the pos of . 0 is the pos of string #attrs = IBus.AttrList ([IBus.AttributeForeground (0x8e2626, -2, 1)]) attrs = IBus.AttrList () # this is the part of tabkey attrs.append(IBus.attr_foreground_new(rgb(0x19,0x73,0xa2), 0, \ len(_phrase) + len(_tbks))) if candi[-2] < 0: # this is a user defined phrase: attrs.append(IBus.attr_foreground_new(rgb(0x77,0x00,0xc3), 0, len(_phrase))) elif candi[-1] > 0: # this is a sys phrase used by user: attrs.append(IBus.attr_foreground_new(rgb(0x00,0x00,0x00), 0, len(_phrase))) else: # this is a system phrase haven't been used: attrs.append(IBus.attr_foreground_new(rgb(0x00,0x00,0x00), 0, len(_phrase))) text = IBus.Text.new_from_string(_phrase + _tbks) i = 0 while attrs.get(i) != None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 self._lookup_table.append_candidate (text) self._lookup_table.set_cursor_visible(True) def filter_candidates (self, candidates): '''Filter candidates if IME is Chinese''' #if self.db._is_chinese and (not self._py_mode): if not self._chinese_mode in(2,3): return candidates[:] bm_index = self._pt.index('category') if self._chinese_mode == 2: # All Chinese characters with simplified Chinese first return filter (lambda x: x[bm_index] & 1, candidates)\ +filter (lambda x: x[bm_index] & (1 << 1) and \ (not x[bm_index] & 1), candidates)\ + filter (lambda x: x[bm_index] & (1 << 2), candidates) elif self._chinese_mode == 3: # All Chinese characters with traditional Chinese first return filter (lambda x: x[bm_index] & (1 << 1), candidates)\ +filter (lambda x: x[bm_index] & 1 and\ (not x[bm_index] & (1<<1)) , candidates)\ + filter (lambda x: x[bm_index] & (1 << 2), candidates) def update_candidates (self): '''Update lookuptable''' # first check whether the IME have defined start_chars if self.db.startchars and ( len(self._chars[0]) == 1 )\ and ( len(self._chars[1]) == 0 ) \ and ( self._chars[0][0] not in self.db.startchars): self._u_chars.append ( self._chars[0][0] ) self._strings.insert ( self._cursor[0], self._chars[0][0] ) self._cursor [0] += 1 self.clear_input() else: if (self._chars[0] == self._chars[2] and self._candidates[0]) \ or self._chars[1]: # if no change in valid input char or we have invalid input, # we do not do sql enquery pass else: # check whether last time we have only one candidate only_one_last = self.one_candidate() # do enquiry self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) if self._tabkey_list: # here we need to consider two parts, table and pinyin # first table if not self._py_mode: if self.db._is_chinese : bm_index = self._pt.index('category') if self._chinese_mode == 0: # simplify Chinese mode self._candidates[0] = self.db.select_words(\ self._tabkey_list, self._onechar, 1 ) elif self._chinese_mode == 1: # traditional Chinese mode self._candidates[0] = self.db.select_words(\ self._tabkey_list, self._onechar, 2 ) else: self._candidates[0] = self.db.select_words(\ self._tabkey_list, self._onechar ) else: self._candidates[0] = self.db.select_words( self._tabkey_list, self._onechar ) else: self._candidates[0] = self.db.select_zi( self._tabkey_list ) self._chars[2] = self._chars[0][:] else: self._candidates[0] =[] if self._candidates[0]: self._candidates[0] = self.filter_candidates (self._candidates[0]) if self._candidates[0]: self.fill_lookup_table() else: if self._chars[0]: ## old manner: #if self._candidates[1]: # #print self._candidates[1] # self._candidates[0] = self._candidates[1] # self._candidates[1] = [] # last_input = self.pop_input () # self.auto_commit_to_preedit () # res = self.add_input( last_input ) # print res # return res #else: # self.pop_input () # self._lookup_table.clear() # self._lookup_table.set_cursor_visible(True) # return False ################### ## new manner, we add new char to invalid input ## chars if not self._chars[1]: # we don't have invalid input chars # here we need to check the last input # is a punctuation or not, if is a punct, # then we use old maner to summit the former valid # candidate if ascii.ispunct (self._chars[0][-1].encode('ascii')) \ or len (self._chars[0][:-1]) \ in self.db.pkeylens \ or only_one_last \ or self._auto_select: # because we use [!@#$%] to denote [12345] # in py_mode, so we need to distinguish them ## old manner: if self._py_mode: if self._chars[0][-1] in "!@#$%": self._chars[0].pop() self._tabkey_list.pop() return True if self._candidates[1]: self._candidates[0] = self._candidates[1] self._candidates[1] = [] last_input = self.pop_input () self.auto_commit_to_preedit () res = self.add_input( last_input ) return res else: self.pop_input () self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) return False else: # this is not a punct or not a valid phrase # last time self._chars[1].append( self._chars[0].pop() ) self._tabkey_list.pop() else: pass self._candidates[0] =[] else: self._lookup_table.clear() self._lookup_table.set_cursor_visible(True) self._candidates[1] = self._candidates[0] return True def commit_to_preedit (self): '''Add select phrase in lookup table to preedit string''' if not self._py_mode: _p_index = self.get_index('phrase') else: _p_index = 8 try: if self._candidates[0]: self._strings.insert(self._cursor[0], self._candidates[0][ self.get_cursor_pos() ][_p_index]) self._cursor [0] += 1 if self._py_mode: self._zi = self._candidates[0][ self.get_cursor_pos() ][_p_index] self.over_input () self.update_candidates () except: pass def auto_commit_to_preedit (self): '''Add select phrase in lookup table to preedit string''' if not self._py_mode: _p_index = self.get_index('phrase') else: _p_index = 8 try: self._u_chars.append( self._chars[0][:] ) self._strings.insert(self._cursor[0], self._candidates[0][ self.get_cursor_pos() ][_p_index]) self._cursor [0] += 1 self.clear_input() self.update_candidates () except: pass def get_aux_strings (self): '''Get aux strings''' input_chars = self.get_input_chars () if input_chars: #aux_string = u' '.join( map( u''.join, self._u_chars + [self._chars[0]] ) ) aux_string = u''.join (self._chars[0]) if self._py_mode: aux_string = aux_string.replace('!','1').replace('@','2').replace('#','3').replace('$','4').replace('%','5') return aux_string aux_string = u'' if self._zi: # we have pinyin result tabcodes = self.db.find_zi_code(self._zi) aux_string = u' '.join(tabcodes) # self._zi = u'' cstr = u''.join(self._strings) if self.db.user_can_define_phrase: if len (cstr ) > 1: aux_string += (u'\t#: ' + self.db.parse_phrase_to_tabkeys (cstr)) return aux_string def fill_lookup_table(self): '''Fill more entries to self._lookup_table if needed. If the cursor in _lookup_table moved beyond current length, add more entries from _candidiate[0] to _lookup_table.''' lookup = self._lookup_table looklen = lookup.get_number_of_candidates() psize = lookup.get_page_size() if (lookup.get_cursor_pos() + psize >= looklen and looklen < len(self._candidates[0])): endpos = looklen + psize batch = self._candidates[0][looklen:endpos] map(self.ap_candidate, batch) def arrow_down(self): '''Process Arrow Down Key Event Move Lookup Table cursor down''' self.fill_lookup_table() res = self._lookup_table.cursor_down() self.update_candidates () if not res and self._candidates[0]: return True return res def arrow_up(self): '''Process Arrow Up Key Event Move Lookup Table cursor up''' res = self._lookup_table.cursor_up() self.update_candidates () if not res and self._candidates[0]: return True return res def page_down(self): '''Process Page Down Key Event Move Lookup Table page down''' self.fill_lookup_table() res = self._lookup_table.page_down() self.update_candidates () if not res and self._candidates[0]: return True return res def page_up(self): '''Process Page Up Key Event move Lookup Table page up''' res = self._lookup_table.page_up() self.update_candidates () if not res and self._candidates[0]: return True return res def select_key(self, char): ''' Commit a candidate in the lookup table which was selected by typing a selection key ''' try: index = self._select_keys.index(char) except ValueError: return False cursor_pos = self._lookup_table.get_cursor_pos() cursor_in_page = self._lookup_table.get_cursor_in_page() current_page_start = cursor_pos - cursor_in_page real_index = current_page_start + index if real_index >= len (self._candidates[0]): # the index given is out of range we do not commit anything return False self._lookup_table.set_cursor_pos(real_index) self.commit_to_preedit () return True def alt_select_key(self, char): '''Remove the candidates in Lookup Table from user_db index.''' try: index = self._select_keys.index(char) except ValueError: return False cursor_pos = self._lookup_table.get_cursor_pos() cursor_in_page = self._lookup_table.get_cursor_in_page() current_page_start = cursor_pos - cursor_in_page real_index = current_page_start + index if len (self._candidates[0]) > real_index: # this index is valid can = self._candidates[0][real_index] if can[-2] < 0: # freq of this candidate is -1, means this a user phrase self.db.remove_phrase (can) # make update_candidates do sql enquiry self._chars[2].pop() self.update_candidates () return True else: return False def get_cursor_pos (self): '''get lookup table cursor position''' return self._lookup_table.get_cursor_pos() def get_lookup_table (self): '''Get lookup table''' return self._lookup_table def is_lt_visible (self): '''Check whether lookup table is visible''' return self._lookup_table.is_cursor_visible () def backspace (self): '''Process backspace Key Event''' self._zi = u'' if self.get_input_chars(): self.pop_input () return True elif self.get_preedit_strings (): self.remove_before_char () return True else: return False def control_backspace (self): '''Process control+backspace Key Event''' self._zi = u'' if self.get_input_chars(): self.over_input () return True elif self.get_preedit_strings (): self.remove_before_string () return True else: return False def delete (self): '''Process delete Key Event''' self._zi = u'' if self.get_input_chars(): return True elif self.get_preedit_strings (): self.remove_after_char () return True else: return False def control_delete (self): '''Process control+delete Key Event''' self._zi = u'' if self.get_input_chars (): return True elif self.get_preedit_strings (): self.remove_after_string () return True else: return False def l_shift (self): '''Process Left Shift Key Event as immediately commit to preedit strings''' if self._chars[0]: self.commit_to_preedit () return True else: return False def r_shift (self): '''Proess Right Shift Key Event as changed between PinYin Mode and Table Mode''' self._zi = u'' if self._chars[0]: self.commit_to_preedit () self._py_mode = not (self._py_mode) return True def l_alt(self): """Left Alt key, cycle cursor to next candidate in the page.""" total = len(self._candidates[0]) if total > 0: lookup = self._lookup_table page_size = lookup.get_page_size() pos = lookup.get_cursor_pos() page = int(pos/page_size) pos += 1 if pos >= (page+1)*page_size or pos >= total: pos = page*page_size res = lookup.set_cursor_pos(pos) return True else: return False def space (self): '''Process space Key Event return (KeyProcessResult,whethercommit,commitstring)''' if self._chars[1]: # we have invalid input, so do not commit return (False,u'') if self._t_chars : # user has input sth istr = self.get_all_input_strings () self.commit_to_preedit () pstr = self.get_preedit_strings () #print "istr: ",istr self.clear() return (True,pstr,istr) else: return (False,u'',u'') def one_candidate (self): '''Return true if there is only one candidate''' return len(self._candidates[0]) == 1 ######################## ### Engine Class ##### #################### class tabengine (IBus.Engine): '''The IM Engine for Tables''' # colors # _phrase_color = 0xffffff # _user_phrase_color = 0xffffff # _new_phrase_color = 0xffffff def __init__ (self, bus, obj_path, db ): super(tabengine,self).__init__ (connection=bus.get_connection(), object_path=obj_path) self._bus = bus # this is the backend sql db we need for our IME # we receive this db from IMEngineFactory #self.db = tabsqlitedb.tabsqlitedb( name = dbname ) self.db = db # this is the parer which parse the input string to key object self._parser = tabdict.parse self._icon_dir = '%s%s%s%s' % (os.getenv('IBUS_TABLE_LOCATION'), os.path.sep, 'icons', os.path.sep) # 0 = english input mode # 1 = table input mode self._mode = 1 # self._ime_py: True / False this IME support pinyin mode self._ime_py = self.db.get_ime_property ('pinyin_mode') if self._ime_py: if self._ime_py.lower() == u'true': self._ime_py = True else: self._ime_py = False else: print 'We could not find "pinyin_mode" entry in database, is it an outdated database?' self._ime_py = False self._status = self.db.get_ime_property('status_prompt').encode('utf8') # now we check and update the valid input characters self._chars = self.db.get_ime_property('valid_input_chars') self._valid_input_chars = [] for _c in self._chars: if _c in tabdict.tab_key_list: self._valid_input_chars.append(_c) del self._chars # check whether we can use '=' and '-' for page_down/up self._page_down_keys = [IBus.KEY_Page_Down, IBus.KEY_KP_Page_Down] self._page_up_keys = [IBus.KEY_Page_Up, IBus.KEY_KP_Page_Up] if '=' not in self._valid_input_chars \ and '-' not in self._valid_input_chars: self._page_down_keys.append (IBus.KEY_equal) self._page_up_keys.append (IBus.KEY_minus) pageup_prop = self.db.get_ime_property('page_up_keys') pagedown_prop = self.db.get_ime_property('page_down_keys') if pageup_prop is not None: self._page_up_keys = [IBus.keyval_from_name(x) for x in pageup_prop.split(",")] if pagedown_prop is not None: self._page_down_keys = [IBus.keyval_from_name(x) for x in pagedown_prop.split(",")] self._pt = self.db.get_phrase_table_index () self._ml = int(self.db.get_ime_property ('max_key_length')) # name for config section self._name = self.db.get_ime_property('name') self._config_section = "engine/Table/%s" % self._name.replace(' ', '_') # config module self._config = self._bus.get_config () self._config.connect ("value-changed", self.config_value_changed_cb) # Containers we used: self._editor = editor(self._config, self._pt, self._valid_input_chars, self._ml, self.db) # some other vals we used: # self._prev_key: hold the key event last time. self._prev_key = None self._prev_char = None self._double_quotation_state = False self._single_quotation_state = False # [EnMode,TabMode] we get TabMode properties from db self._full_width_letter = [ variant_to_value(self._config.get_value( self._config_section, "EnDefFullWidthLetter")), variant_to_value(self._config.get_value( self._config_section, "TabDefFullWidthLetter")) ] if self._full_width_letter[0] == None: self._full_width_letter[0] = False if self._full_width_letter[1] == None: self._full_width_letter[1] = self.db.get_ime_property('def_full_width_letter').lower() == u'true' self._full_width_punct = [ variant_to_value(self._config.get_value( self._config_section, "EnDefFullWidthPunct")), variant_to_value(self._config.get_value( self._config_section, "TabDefFullWidthPunct")) ] if self._full_width_punct[0] == None: self._full_width_punct[0] = False if self._full_width_punct[1] == None: self._full_width_punct[1] = self.db.get_ime_property('def_full_width_punct').lower() == u'true' # some properties we will involved, Property is taken from scim. #self._setup_property = Property ("setup", _("Setup")) self._auto_commit = variant_to_value(self._config.get_value( self._config_section, "AutoCommit")) if self._auto_commit == None: self._auto_commit = self.db.get_ime_property('auto_commit').lower() == u'true' self._auto_select = variant_to_value(self._config.get_value( self._config_section, "AutoSelect")) if self._auto_select == None: if self.db.get_ime_property('auto_select') != None: self._auto_select = self.db.get_ime_property('auto_select').lower() == u'true' else: self._auto_select = False # the commit phrases length self._len_list = [0] # connect to SpeedMeter #try: # bus = dbus.SessionBus() # user = os.path.basename( os.path.expanduser('~') ) # self._sm_bus = bus.get_object ("org.ibus.table.SpeedMeter.%s"\ # % user, "/org/ibus/table/SpeedMeter") # self._sm = dbus.Interface(self._sm_bus,\ # "org.ibus.table.SpeedMeter") #except: # self._sm = None #self._sm_on = False self._on = False self.reset () def reset (self): self._editor.clear () self._double_quotation_state = False self._single_quotation_state = False self._prev_key = None #self._editor._onechar = False self._init_properties () self._update_ui () def do_destroy(self): self.reset () self.do_focus_out () #self.db.sync_usrdb () super(tabengine,self).destroy() def _init_properties (self): self.properties= IBus.PropList () self._status_property = IBus.Property(key=u'status', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._status_property) if self.db._is_chinese: self._cmode_property = IBus.Property(key=u'cmode', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._cmode_property) self._letter_property = IBus.Property(key=u'letter', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._letter_property) self._punct_property = IBus.Property(key=u'punct', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._punct_property) self._py_property = IBus.Property(key=u'py_mode', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._py_property) self._onechar_property = IBus.Property(key=u'onechar', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._onechar_property) self._auto_commit_property = IBus.Property(key=u'acommit', label=None, icon=None, tooltip=None, sensitive=True, visible=True) self.properties.append(self._auto_commit_property) self.register_properties (self.properties) self._refresh_properties () def _refresh_properties (self): '''Method used to update properties''' # taken and modified from PinYin.py :) if self._mode == 1: # refresh mode if self._status == u'CN': self._set_property(self._status_property, 'chinese.svg', _('Chinese Mode'), _('Switch to English mode')) else: self._set_property(self._status_property, 'ibus-table.svg', self._status, _('Switch to English mode')) else: self._set_property(self._status_property, 'english.svg', _('English Mode'), _('Switch to Table mode')) self.update_property(self._status_property) if self._full_width_letter[self._mode]: self._set_property(self._letter_property, 'full-letter.svg', _('Full Letter'), _('Switch to half-width letter')) else: self._set_property(self._letter_property, 'half-letter.svg', _('Half Letter'), _('Switch to full-width letter')) self.update_property(self._letter_property) if self._full_width_punct[self._mode]: self._set_property(self._punct_property, 'full-punct.svg', _('Full-width Punctuation'), _('Switch to half-width punctuation')) else: self._set_property(self._punct_property, 'half-punct.svg', _('Half-width Punctuation'), _('Switch to full-width punctuation')) self.update_property(self._punct_property) if self._editor._py_mode: self._set_property(self._py_property, 'py-mode.svg', _('PinYin Mode'), _('Switch to Table mode')) else: self._set_property(self._py_property, 'tab-mode.svg', _('Table Mode'), _('Switch to PinYin mode')) self.update_property(self._py_property) if self._editor._onechar: self._set_property(self._onechar_property, 'onechar.svg', _('Single Char Mode'), _('Switch to phrase mode')) else: self._set_property(self._onechar_property, 'phrase.svg', _('Phrase Mode'), _('Switch to single char mode')) self.update_property(self._onechar_property) if self._auto_commit: self._set_property(self._auto_commit_property, 'acommit.svg', _('Direct Commit Mode'), _('Switch to normal commit mode, which use space to commit')) else: self._set_property(self._auto_commit_property, 'ncommit.svg', _('Normal Commit Mode'), _('Switch to direct commit mode')) self.update_property(self._auto_commit_property) # the chinese_mode: if self.db._is_chinese: if self._editor._chinese_mode == 0: self._set_property(self._cmode_property, 'sc-mode.svg', _('Simplified Chinese Mode'), _('Switch to Traditional Chinese mode')) elif self._editor._chinese_mode == 1: self._set_property(self._cmode_property, 'tc-mode.svg', _('Traditional Chinese Mode'), _('Switch to Simplify Chinese first Big Charset Mode')) elif self._editor._chinese_mode == 2: self._set_property(self._cmode_property, 'scb-mode.svg', _('Simplified Chinese First Big Charset Mode'), _('Switch to Traditional Chinese first Big Charset Mode')) elif self._editor._chinese_mode == 3: self._set_property(self._cmode_property, 'tcb-mode.svg', _('Traditional Chinese First Big Charset Mode'), _('Switch to Big Charset Mode')) elif self._editor._chinese_mode == 4: self._set_property(self._cmode_property, 'cb-mode.svg', _('Big Chinese Mode'), _('Switch to Simplified Chinese Mode')) self.update_property(self._cmode_property) def _set_property (self, property, icon, label, tooltip): property.set_icon ( u'%s%s' % (self._icon_dir, icon ) ) property.set_label (IBus.Text.new_from_string(unicode(label))) property.set_tooltip (IBus.Text.new_from_string(unicode(tooltip))) def _change_mode (self): '''Shift input mode, TAB -> EN -> TAB ''' self._mode = int (not self._mode) self.reset () self._update_ui () def do_property_activate (self, property, prop_state = IBus.PropState.UNCHECKED): '''Shift property''' if property == u"status": self._change_mode () elif property == u'py_mode' and self._ime_py: self._editor.r_shift () elif property == u'onechar': self._editor._onechar = not self._editor._onechar self._config.set_value(self._config_section, "OneChar", GLib.Variant.new_boolean(self._editor._onechar)) elif property == u'acommit': self._auto_commit = not self._auto_commit self._config.set_value( self._config_section, "AutoCommit", GLib.Variant.new_boolean(self._auto_commit)) elif property == u'letter': self._full_width_letter [self._mode] = not self._full_width_letter [self._mode] if self._mode: self._config.set_value(self._config_section, "TabDefFullWidthLetter", GLib.Variant.new_boolean(self._full_width_letter [self._mode])) else: self._config.set_value(self._config_section, "EnDefFullWidthLetter", GLib.Variant.new_boolean(self._full_width_letter [self._mode])) elif property == u'punct': self._full_width_punct [self._mode] = not self._full_width_punct [self._mode] if self._mode: self._config.set_value(self._config_section, "TabDefFullWidthPunct", GLib.Variant.new_boolean(self._full_width_punct [self._mode])) else: self._config.set_value(self._config_section, "EnDefFullWidthPunct", GLib.Variant.new_boolean(self._full_width_punct [self._mode])) elif property == u'cmode': self._editor.change_chinese_mode() self.reset() self._refresh_properties () # elif property == "setup": # Need implementation # self.start_helper ("96c07b6f-0c3d-4403-ab57-908dd9b8d513") # at last invoke default method def _update_preedit (self): '''Update Preedit String in UI''' _str = self._editor.get_preedit_strings () if _str == u'': super(tabengine, self).update_preedit_text(IBus.Text.new_from_string(u''), 0, False) else: attrs = IBus.AttrList() res = patt_edit.match (_str) if res: _str = u'' ures = patt_uncommit.match (res.group(1)) if ures: _str=u''.join (ures.groups()) lc = len (ures.group(1) ) lu = len (ures.group(2) ) attrs.append(IBus.attr_foreground_new(rgb(0x1b,0x3f,0x03),0,lc)) attrs.append(IBus.attr_foreground_new(rgb(0x08,0x95,0xa2),lc,lu)) lg1 = len (_str) else: _str += res.group (1) lg1 = len ( res.group(1) ) attrs.append(IBus.attr_foreground_new(rgb(0x1b,0x3f,0x03),0,lg1)) _str += res.group(2) _str += res.group(3) lg2 = len ( res.group(2) ) lg3 = len ( res.group(3) ) attrs.append(IBus.attr_foreground_new(rgb(0x0e,0x0e,0xa0),lg1,lg2)) attrs.append(IBus.attr_foreground_new(rgb(0x1b,0x3f,0x03),lg1+lg2,lg3)) else: attrs.append(IBus.attr_foreground_new(rgb(0x1b,0x3f,0x03),0,len(_str))) # because ibus now can only insert preedit into txt, so... attrs = IBus.AttrList() attrs.append(IBus.attr_underline_new(IBus.AttrUnderline.SINGLE, 0, len(_str))) text = IBus.Text.new_from_string(_str) i = 0 while attrs.get(i) != None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 super(tabengine, self).update_preedit_text(text, self._editor.get_caret(), True) def _update_aux (self): '''Update Aux String in UI''' _ic = self._editor.get_aux_strings () if _ic: attrs = IBus.AttrList() attrs.append(IBus.attr_foreground_new(rgb(0x95,0x15,0xb5),0, len(_ic))) text = IBus.Text.new_from_string(_ic) i = 0 while attrs.get(i) != None: attr = attrs.get(i) text.append_attribute(attr.get_attr_type(), attr.get_value(), attr.get_start_index(), attr.get_end_index()) i += 1 super(tabengine, self).update_auxiliary_text(text, True) else: self.hide_auxiliary_text() #self.update_aux_string (u'', None, False) def _update_lookup_table (self): '''Update Lookup Table in UI''' if self._editor.is_empty (): self.hide_lookup_table() return self.update_lookup_table(self._editor.get_lookup_table(), True) def _update_ui (self): '''Update User Interface''' self._update_lookup_table () self._update_preedit () self._update_aux () #def add_string_len(self, astring): # if self._sm_on: # try: # self._sm.Accumulate(len(astring)) # except: # pass def commit_string (self,string): self._editor.clear () self._update_ui () super(tabengine,self).commit_text(IBus.Text.new_from_string(string)) self._prev_char = string[-1] def _convert_to_full_width (self, c): '''convert half width character to full width''' if c in [u".", u"\\", u"^", u"_", u"$", u"\"", u"'", u">", u"<", u"[", u"]", u"{", u"}" ]: if c == u".": if self._prev_char and self._prev_char.isdigit () \ and self._prev_key and chr (self._prev_key.code) == self._prev_char: return u"." else: return u"\u3002" elif c == u"\\": return u"\u3001" elif c == u"^": return u"\u2026\u2026" elif c == u"_": return u"\u2014\u2014" elif c == u"$": return u"\uffe5" elif c == u"\"": self._double_quotation_state = not self._double_quotation_state if self._double_quotation_state: return u"\u201c" else: return u"\u201d" elif c == u"'": self._single_quotation_state = not self._single_quotation_state if self._single_quotation_state: return u"\u2018" else: return u"\u2019" elif c == u"<": if self._mode: return u"\u300a" elif c == u">": if self._mode: return u"\u300b" elif c == u"[": if self._mode: return u"\u300c" elif c == u"]": if self._mode: return u"\u300d" elif c == u"{": if self._mode: return u"\u300e" elif c == u"}": if self._mode: return u"\u300f" return unichar_half_to_full (c) def _match_hotkey (self, key, code, mask): if key.code == code and key.mask == mask: if self._prev_key and key.code == self._prev_key.code and key.mask & IBus.ModifierType.RELEASE_MASK: return True if not key.mask & IBus.ModifierType.RELEASE_MASK: return True return False def do_process_key_event(self, keyval, keycode, state): '''Process Key Events Key Events include Key Press and Key Release, modifier means Key Pressed ''' key = KeyEvent(keyval, state & IBus.ModifierType.RELEASE_MASK == 0, state) # ignore NumLock mask key.mask &= ~IBus.ModifierType.MOD2_MASK result = self._process_key_event (key) self._prev_key = key return result def _process_key_event (self, key): '''Internal method to process key event''' # Match mode switch hotkey if not self._editor._t_chars and ( self._match_hotkey (key, IBus.KEY_Shift_L, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK)): self._change_mode () return True # Match full half letter mode switch hotkey if self._match_hotkey (key, IBus.KEY_space, IBus.ModifierType.SHIFT_MASK): self.do_property_activate ("letter") return True # Match full half punct mode switch hotkey if self._match_hotkey (key, IBus.KEY_period, IBus.ModifierType.CONTROL_MASK): self.do_property_activate ("punct") return True # we ignore all hotkeys # if key.mask & IBus.ModifierType.MOD1_MASK: # return False # Ignore key release event # if key.mask & IBus.ModifierType.RELEASE_MASK: # return True if self._mode: return self._table_mode_process_key_event (key) else: return self._english_mode_process_key_event (key) def _english_mode_process_key_event (self, key): '''English Mode Process Key Event''' # Ignore key release event if key.mask & IBus.ModifierType.RELEASE_MASK: return True if key.code >= 128: return False # we ignore all hotkeys here if key.mask & (IBus.ModifierType.CONTROL_MASK|IBus.ModifierType.MOD1_MASK): return False keychar = unichr (key.code) if ascii.ispunct (key.code): # if key code is a punctation if self._full_width_punct[self._mode]: self.commit_string (self._convert_to_full_width (keychar)) return True else: self.commit_string (keychar) return True # then, the key code is a letter or digit if self._full_width_letter[self._mode]: # in full width letter mode self.commit_string (self._convert_to_full_width (keychar)) return True else: return False # should not reach there return False def _table_mode_process_key_event (self, key): '''Xingma Mode Process Key Event''' cond_letter_translate = lambda (c): \ self._convert_to_full_width (c) if self._full_width_letter [self._mode] else c cond_punct_translate = lambda (c): \ self._convert_to_full_width (c) if self._full_width_punct [self._mode] else c # We have to process the pinyin mode change key event here, # because we ignore all Release event below. if self._match_hotkey (key, IBus.KEY_Shift_R, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) and self._ime_py: res = self._editor.r_shift () self._refresh_properties () self._update_ui () return res # process commit to preedit if self._match_hotkey (key, IBus.KEY_Shift_R, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK) or self._match_hotkey (key, IBus.KEY_Shift_L, IBus.ModifierType.SHIFT_MASK | IBus.ModifierType.RELEASE_MASK): res = self._editor.l_shift () self._update_ui () return res # Left ALT key to cycle candidates in the current page. if self._match_hotkey (key, IBus.KEY_Alt_L, IBus.ModifierType.MOD1_MASK | IBus.ModifierType.RELEASE_MASK): res = self._editor.l_alt () self._update_ui () return res # Match single char mode switch hotkey if self._match_hotkey (key, IBus.KEY_comma, IBus.ModifierType.CONTROL_MASK): self.do_property_activate ( u"onechar" ) return True # Match direct commit mode switch hotkey if self._match_hotkey (key, IBus.KEY_slash, IBus.ModifierType.CONTROL_MASK): self.do_property_activate ( u"acommit" ) return True # Match Chinese mode shift if self._match_hotkey (key, IBus.KEY_semicolon, IBus.ModifierType.CONTROL_MASK): self.do_property_activate ( u"cmode" ) return True # Match speedmeter shift #if self._match_hotkey (key, IBus.KEY_apostrophe, IBus.ModifierType.CONTROL_MASK): # self._sm_on = not self._sm_on # if self._sm_on: # self._sm.Show () # else: # self._sm.Hide () # return True # Ignore key release event now :) if key.mask & IBus.ModifierType.RELEASE_MASK: return True # keychar = unichr (key.code) if self._editor.is_empty (): # we have not input anything if key.code >= 32 and key.code <= 127 and ( keychar not in self._valid_input_chars ) \ and (not (key.mask & (IBus.ModifierType.MOD1_MASK | IBus.ModifierType.CONTROL_MASK))): if key.code == IBus.KEY_space: #self.commit_string (cond_letter_translate (keychar)) # little hack to make ibus to input space in gvim :) if self._full_width_letter [self._mode]: self.commit_string (cond_letter_translate (keychar)) return True else: return False if ascii.ispunct (key.code): self.commit_string (cond_punct_translate (keychar)) return True if ascii.isdigit (key.code): self.commit_string (cond_letter_translate (keychar)) return True elif (key.code < 32 or key.code > 127) and ( keychar not in self._valid_input_chars ) \ and(not self._editor._py_mode): return False if key.code == IBus.KEY_Escape: self.reset () self._update_ui () return True elif key.code in (IBus.KEY_Return, IBus.KEY_KP_Enter): commit_string = self._editor.get_all_input_strings () self.commit_string (commit_string) return True elif key.code in (IBus.KEY_Down, IBus.KEY_KP_Down) : res = self._editor.arrow_down () self._update_ui () return res elif key.code in (IBus.KEY_Up, IBus.KEY_KP_Up): res = self._editor.arrow_up () self._update_ui () return res elif key.code in (IBus.KEY_Left, IBus.KEY_KP_Left) and key.mask & IBus.ModifierType.CONTROL_MASK: res = self._editor.control_arrow_left () self._update_ui () return res elif key.code in (IBus.KEY_Right, IBus.KEY_KP_Right) and key.mask & IBus.ModifierType.CONTROL_MASK: res = self._editor.control_arrow_right () self._update_ui () return res elif key.code in (IBus.KEY_Left, IBus.KEY_KP_Left): res = self._editor.arrow_left () self._update_ui () return res elif key.code in (IBus.KEY_Right, IBus.KEY_KP_Right): res = self._editor.arrow_right () self._update_ui () return res elif key.code == IBus.KEY_BackSpace and key.mask & IBus.ModifierType.CONTROL_MASK: res = self._editor.control_backspace () self._update_ui () return res elif key.code == IBus.KEY_BackSpace: res = self._editor.backspace () self._update_ui () return res elif key.code == IBus.KEY_Delete and key.mask & IBus.ModifierType.CONTROL_MASK: res = self._editor.control_delete () self._update_ui () return res elif key.code == IBus.KEY_Delete: res = self._editor.delete () self._update_ui () return res elif ( keychar in self._editor.get_select_keys() and self._editor._candidates[0] and key.mask & IBus.ModifierType.CONTROL_MASK ): res = self._editor.select_key (keychar) self._update_ui () return res elif ( keychar in self._editor.get_select_keys() and self._editor._candidates[0] and key.mask & IBus.ModifierType.MOD1_MASK ): res = self._editor.alt_select_key (keychar) self._update_ui () return res elif key.code == IBus.KEY_space: # if space is one of "page_down_keys" change to next page # on lookup page if IBus.KEY_space in self._page_down_keys: res = self._editor.page_down() self._update_ui () return res else: o_py = self._editor._py_mode sp_res = self._editor.space () #return (KeyProcessResult,whethercommit,commitstring) if sp_res[0]: if self._auto_select: self.commit_string ("%s " %sp_res[1]) else: self.commit_string (sp_res[1]) #self.add_string_len(sp_res[1]) self.db.check_phrase (sp_res[1], sp_res[2]) else: if sp_res[1] == u' ': self.commit_string (cond_letter_translate (u" ")) if o_py != self._editor._py_mode: self._refresh_properties () self._update_ui () return True # now we ignore all else hotkeys elif key.mask & (IBus.ModifierType.CONTROL_MASK|IBus.ModifierType.MOD1_MASK): return False elif key.mask & IBus.ModifierType.MOD1_MASK: return False elif keychar in self._valid_input_chars or \ ( self._editor._py_mode and \ keychar in u'abcdefghijklmnopqrstuvwxyz!@#$%' ): if self._auto_commit and ( len(self._editor._chars[0]) == self._ml \ or len (self._editor._chars[0]) in self.db.pkeylens )\ and not self._editor._py_mode: # it is time to direct commit sp_res = self._editor.space () #return (whethercommit,commitstring) if sp_res[0]: self.commit_string (sp_res[1]) #self.add_string_len(sp_res[1]) self.db.check_phrase (sp_res[1],sp_res[2]) res = self._editor.add_input ( keychar ) if not res: if ascii.ispunct (key.code): key_char = cond_punct_translate (keychar) else: key_char = cond_letter_translate (keychar) sp_res = self._editor.space () #return (KeyProcessResult,whethercommit,commitstring) if sp_res[0]: self.commit_string (sp_res[1] + key_char) #self.add_string_len(sp_res[1]) self.db.check_phrase (sp_res[1],sp_res[2]) return True else: self.commit_string ( key_char ) return True else: if self._auto_commit and self._editor.one_candidate () and \ (len(self._editor._chars[0]) == self._ml \ or not self.db._is_chinese): # it is time to direct commit sp_res = self._editor.space () #return (whethercommit,commitstring) if sp_res[0]: self.commit_string (sp_res[1]) #self.add_string_len(sp_res[1]) self.db.check_phrase (sp_res[1], sp_res[2]) return True self._update_ui () return True elif key.code in self._page_down_keys \ and self._editor._candidates[0]: res = self._editor.page_down() self._update_ui () return res elif key.code in self._page_up_keys \ and self._editor._candidates[0]: res = self._editor.page_up () self._update_ui () return res elif keychar in self._editor.get_select_keys() and self._editor._candidates[0]: input_keys = self._editor.get_all_input_strings () res = self._editor.select_key (keychar) if res: o_py = self._editor._py_mode commit_string = self._editor.get_preedit_strings () self.commit_string (commit_string) #self.add_string_len(commit_string) if o_py != self._editor._py_mode: self._refresh_properties () self._update_ui () # modify freq info self.db.check_phrase (commit_string, input_keys) return True elif key.code <= 127: if not self._editor._candidates[0]: commit_string = self._editor.get_all_input_strings () else: self._editor.commit_to_preedit () commit_string = self._editor.get_preedit_strings () # we need to take care of the py_mode here :) py_mode = self._editor._py_mode self._editor.clear () if py_mode: self._refresh_properties () if ascii.ispunct (key.code): self.commit_string ( commit_string + cond_punct_translate(keychar)) else: self.commit_string ( commit_string + cond_letter_translate(keychar)) return True return False # below for initial test def do_focus_in (self): if self._on: self.register_properties (self.properties) self._refresh_properties () self._update_ui () #try: # if self._sm_on: # self._sm.Show () # else: # self._sm.Hide () #except: # pass def do_focus_out (self): #try: # self._sm.Hide() #except: # pass pass def do_enable (self): #try: # self._sm.Reset() #except: # pass self._on = True self.do_focus_in() def do_disable (self): self.reset() #try: # self._sm.Hide() #except: # pass self._on = False def do_page_up (self): if self._editor.page_up (): self._update_ui () return True return False def do_page_down (self): if self._editor.page_down (): self._update_ui () return True return False def config_section_normalize(self, section): # This function replaces _: with - in the dconf # section and converts to lower case to make # the comparison of the dconf sections work correctly. # I avoid using .lower() here because it is locale dependent, # when using .lower() this would not achieve the desired # effect of comparing the dconf sections case insentively # in some locales, it would fail for example if Turkish # locale (tr_TR.UTF-8) is set. if type(section) == type(u''): # translate() does not work in Python’s internal Unicode type section = section.encode('utf-8') return re.sub(r'[_:]', r'-', section).translate( string.maketrans(string.ascii_uppercase, string.ascii_lowercase )) def config_value_changed_cb (self, config, section, name, value): if self.config_section_normalize(self._config_section) != self.config_section_normalize(section): return print "config value %(n)s for engine %(en)s changed" %{'n': name, 'en': self._name} value = variant_to_value(value) if name == u'autocommit': self._auto_commit = value self._refresh_properties() return elif name == u'chinesemode': self._editor._chinese_mode = value self._refresh_properties() return elif name == u'endeffullwidthletter': self._full_width_letter[0] = value self._refresh_properties() return elif name == u'endeffullwidthpunct': self._full_width_punct[0] = value self._refresh_properties() return elif name == u'lookuptableorientation': self._editor._lookup_table.set_orientation (value) return elif name == u'lookuptableselectkeys': self._editor.set_select_keys (value) return elif name == u'onechar': self._editor._onechar = value self._refresh_properties() return elif name == u'tabdeffullwidthletter': self._full_width_letter[1] = value self._refresh_properties() return elif name == u'tabdeffullwidthpunct': self._full_width_punct[1] = value self._refresh_properties() return # for further implementation :) @classmethod def CONFIG_VALUE_CHANGED(cls, bus, section, name, value): config = bus.get_config() if section != self._config_section: return @classmethod def CONFIG_RELOADED(cls, bus): config = bus.get_config() if section != self._config_section: return
修改文件时间
将文件时间修改为当前时间的前一年
删除文件