SunPinyin代码导读(十二)
class CIMIClassicVIew {
m_CursorBone: 当前光标所在的Bone
m_CursorIdx: 光标在m_CursorBone中的位置索引
m_CandiBone: 候选列表起始的Bone
m_CandiFirst: 当前窗口中第一条候选在整个候选列表中的索引
m_TailSetence:从m_CandiFirst开始的尾句
};
考察下面的例子,m_CursorBone指向的是'yin'所在的Bone;m_CursorIdx为2,指向的是'n'所在的位置;而m_CandiBone指向的是'pin'所在的Bone;因为没有翻页,所以m_CandiFirst为0;而候选1,即“拼音输入”,就是m_TailSetence。


在经典风格中,向左移动光标,意味着用户可能要修正以前的UserSelection,因此要清除以前的用户选择并重新搜索。而向后移动,后续的可能操作是插入、删除和添加等操作,不影响当下的候选结果,因此不会重新进行搜索。
CIMIClassicView::moveHome(changeMask, searchAgain):
将[firstBone, m_CursorBone]内所有的用户选择都清除,返回开始新搜索的Bone节点。如果存在用户选择,则从firstBone重新搜索。如果不存在用户选择,则返回lastBone。CIMIClassicView::moveLeft(changeMask, searchAgain):
如果m_CursorIdx(光标在m_CursorBone中的索引)大于0,则减去1,返回lastBone(即不影响当前的候选结果)。如果m_CursorIdx为0,并且m_CursorBone不是firstBone,则将m_CursorBone左移一个单位,如果移出了当前的候选词范围(也就是进入了前一个候选词范围),则调用m_pIC->cancelSelection()取消其所在的UserSelection,然后调用getCandidates()重新得到候选,将m_CursorIdx设置为m_CursorBone中拼音字符串儿的长度(如果m_CursorBone不是一个拼音类型的Bone,则m_CursorIdx为0)。最后,返回新搜索的起始Bone节点。CIMIClassicView::moveLeftSyllable(changeMask, searchAgain):
过程和上面的类似,只不过移动是以Bone为单位的,且移动之后,m_CursorIdx设置为0。CIMIClassicView::moveRight(changeMask):
如果m_CursorIdx尚未到达m_CursorBone的尾部,则m_CursorIdx++并返回。如果已到尾部,若m_CursorBone是一个拼音类型的Bone节点,则m_CursorIdx++(相当于一个音节的边界);否则将m_CursorIdx设置为0,且m_CursorBone向右移动一个单位。最后一种可能(m_CursorIdx == m_CursorBone->m_String.size()),是光标位于音节边界上,将m_CursorIdx设置为0,且m_CursorBone向右移动一个单位,并返回。CIMIClassicView::moveRightSyllable(changeMask):
将m_CursorBone向右移动一个单位,并相应地设置m_CursorIdx。CIMIClassicView::moveEnd(changeMask):
将m_CursorBone移动到结尾。CIMIClassicView::makeSelection(idx, mask):
idx是在当前候选窗口中的索引,和m_CandiFirst相加,得到在整个候选列表中的索引。如果idx<0,则提交preedit并重置IC,然后返回。如果idx在候选列表的范围内,则得到索引下的候选对象cand,调用m_pIC->makeSelection(cand)设置用户选择。将m_CandiBone指向cand的结束位置(还记得么,[m_BoneStart, m_BoneEnd)是候选词对应的区间),如果它是不是一个拼音节点且未到达尾节点,则将m_CandiBone向右移动。如果一直移动到了尾节点,则提交preedit并重置IC;否则,如果m_Cursor位于[cand.m_BoneStart, m_CandiBone)之间,则将m_Cursor指向m_CandiBone,且将m_CursorIdx设置为0。然后将m_CandiFirst设置为0,调用getCandidates()来得到新的候选。CIMIClassicView::erase(bLeft, changeMask):
bLeft标识是向左还是向右进行删除。如果向左删除,则调用moveLeft()将光标向左移动一个单位。然后,如果m_CursorIdx指向的是音节边界的位置(即m_CursorIdx == m_CursorBone->m_String.size()),且当前光标是用户确定的边界,则调用m_pIC->modifyAndReseg()对该部分重新节点进行切分和搜索,如果这影响到候选列表,则调用getCandidates()重新获取;如果当前光标不是用户确定的边界,且要向右删除,则调用moveRight()将光标向右移动一个单位。如果m_CursorIdx并非指向音阶边界的位置,则修改光标内的拼音字符串,并调用m_pIC->modifyAndReseg()对该部分节点进行重新切分和搜索,如果这影响到候选列表,则调用getCandidates()重新获取。CIMIClassicView::insertPinyin(keyvalue, changeMask):
如果m_CursorBone是最后一个Bone(也就是在尾部添加拼音字母的情况),则将keyvalue作为一个自动切分的拼音节点,加到一个新的列表skel中,并将m_CursorBone设置为skel.begin(),且m_CursorIdx为1(m_CursorIdx指向的是音阶边界,因为Bone中只有一个拼音字母)。如果m_CursorBone不是一个拼音节点,当m_CursorIdx>0时(通常不会发生这种情况),将[0..cursorIdx)、keyvalue、 [cursorIdx..end)这三个字符串构造为Bone,加入到列表skel中,cursor2自加,m_CursorBone指向中间的Bone,m_CursorIdx设置为1;当m_CursorIdx为0时,将keyvalue作为一个自动切分的拼音节点,加到一个列表skel中,并将m_CursorBone设置为skel.begin(),且m_CursorIdx为0。最后是插入拼音字母的情况,将m_CursorBone压入到skel中,且将keyvalue附加到当前Bone的拼音字符串的尾部,m_CursorBone为skel.begin(),m_CursorIdx自加,且cursor2自加。然后调用m_pIC->modifyAndReseg()对该部分Bone节点重新切分并搜索,如果这影响到候选列表,则调用getCandidates()重新获取。还有其它的一些insert方法,例如insertNormalChar()、insertBoundary(),都会涉及到对Bone列表的修改,而重新进行切分搜索,并获取更新的候选列表。这里就不多作介绍了。
下一回,我们将介绍“History Cache”相关的内容。

