Newer
Older
scim-wnn / scim-wnn / src / romkan.cpp
/***************************************************************************
 *   Copyright (C) 2004 by TAM(Teppei Tamra)                               *
 *   tam-t@par.odn.ne.jp                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "romkan.h"
#include "romkan_table.h"
#include "scim_wnn_def.h"

#ifdef HAVE_CONFIG_H
  #include <config.h>
#endif

// 国際化のおまじない。
#ifdef HAVE_GETTEXT
  #include <libintl.h>
  #define _(String) dgettext(GETTEXT_PACKAGE,String)
  #define N_(String) (String)
#else
  #define _(String) (String)
  #define N_(String) (String)
  #define bindtextdomain(Package,Directory)
  #define textdomain(domain)
  #define bind_textdomain_codeset(domain,codeset)
#endif

Romkan::Romkan(ConfigPointer cfg) : PreEditor(cfg)
{
    reset();
    iconvert.set_encoding ("EUC-JP");
    mode = ROMA;
    init();
}


Romkan::~Romkan()
{
}


/*!
    \fn Romkan::loadTable(const String &filename)
 */
void Romkan::loadTable(const String &filename)
{
    RomkanTable.clear();
    keepTable.clear();
    
    FILE *f = fopen(filename.c_str(),"r");
    if (!f) return;
    
    while(-1) {
        char s[256];
        if(fgets(s,256,f) == NULL) break;
        String k,r;
        unsigned int i = 0;
        for(;s[i];i ++) {
            if (s[i] == ' ') {
                if (k.size()) break;
                else continue;
            }
            if (s[i] == '#') break;
            if ((s[i] == '\\') && (s[i + 1] != 0)) {
                i ++;
            }
            k += s[i];
        }
        if ((!k.size()) || (s[i] == 0) || (s[i] == '#')) continue;
        i ++;
        for(;s[i];i ++) {
            if ((s[i] == '#') || (s[i] == '\n')) break;
            if (s[i] == ' ') {
                if (r.size()) break;
                else continue;
            }
            if ((s[i] == '\\') && (s[i + 1] != 0)) {
                i ++;
            }
            r += s[i];
        }
        if (!r.size()) continue;
        RomkanTable.insert(pair<String,WideString>(k,utf8_mbstowcs(r)));
        
        for(unsigned int j = k.length();j > 1;j --) {
            String keep = k.substr(0,j - 1);
            if ((keepTable.find(keep) == keepTable.end()) && (RomkanTable.find(keep) == RomkanTable.end())) {
                keepTable.insert(keep);
            }
        }
    }
    fclose(f);
        
}


/*!
    \fn Romkan::init()
 */
void Romkan::init()
{
    nnMode = config->read(SCIM_CONFIG_WNN_ROMKAN_NNMODE,SCIM_DEFAULT_WNN_ROMKAN_NNMODE);
    scim_string_to_key_list(key_ascii_mode,
        config->read(String(SCIM_CONFIG_WNN_KEY_ROMKAN_ASCIIMODE),
            String(SCIM_DEFAULT_WNN_KEY_ROMKAN_ASCIIMODE)));
    scim_string_to_key_list(key_wascii_mode,
        config->read(String(SCIM_CONFIG_WNN_KEY_ROMKAN_WASCIIMODE),
            String(SCIM_DEFAULT_WNN_KEY_ROMKAN_WASCIIMODE)));
    String rk_table = config->read(SCIM_CONFIG_WNN_ROMKAN_TABLE_FILE,String(SCIM_DEFAULT_WNN_ROMKAN_TABLE_FILE));
    
    if (rk_table.size()) {
        loadTable(rk_table);
        return;
    }

    RomkanTable.clear();
    keepTable.clear();

    unsigned int i = 0;
    while(strcmp(_RomkanTable[i],"") != 0) {
        WideString w;
        String s = _RomkanTable[i];
        iconvert.convert(w,String(_RomkanTable[i + 1]));
        RomkanTable.insert(pair<String,WideString>(s,w));

        for(unsigned int j = s.length();j > 1;j --) {
            String k = s.substr(0,j - 1);
            if ((keepTable.find(k) == keepTable.end()) && (RomkanTable.find(k) == RomkanTable.end())) {
                keepTable.insert(k);
            }
        }
        i += 2;
    }
    

}




/*!
    \fn Romkan::setPos(int p)
 */
void Romkan::setPos(int p)
{
    if (p < 0) p = 0;
    else if (p > getTextLength()) p = getTextLength();
    pos = p;
    buf.clear();
}


/*!
    \fn Romkan::clear()
 */
void Romkan::clear()
{
    text.clear();
    buf.clear();
}


/*!
    \fn Romkan::insert(char k)
 */
WideString Romkan::insert(char k)
{
    String s;
    s = k;
    if (k == 0) return(text);
    switch(mode) {
        case ASCII: {
            buf.clear();
            text = text.substr(0,pos) + utf8_mbstowcs(s) + text.substr(pos);
            pos ++;
            return(text);
            break;
        }
        case WASCII: {
            buf.clear();
            WideString w = utf8_mbstowcs(s);
            convHanZen(w,pos);
            text = text.substr(0,pos) + w + text.substr(pos);
            pos ++;
            return(text);
            break;
        }
        case ROMA: {
            buf += s;
            text = text.substr(0,pos) + utf8_mbstowcs(s) + text.substr(pos);
            pos ++;
            return(eval());
            break;
        }
    }
    return(text);
}


/*!
    \fn Romkan::eval()
 */
WideString Romkan::eval()
{
    // エヴァる。

    if (buf.length() == 2) {

        // n+母音以外は「ん」+子音である
        // ただし、nyは除外である。
        if (buf[0] == 'n') {
            String b = "aiueoy";
            if (nnMode) b += "n";
            bool boin = false;
            for(unsigned int i = 0;i < b.length();i ++) {
                if (buf[1] == b[i]) boin = true;
            }
            if (!boin) {
                text = text.substr(0,pos - 2) + convChars[KANA_N] + text.substr(pos - 1);
                buf = buf.substr(buf.length() - 1,1);
            }
        }

        // 同じ文字が2文字続くとそれは「っ」+子音である。母音の連打がbufに残ってはいないはず。
        else if (buf[0] == buf[1]) {
            text = text.substr(0,pos - 2) + convChars[KANA_XTU] + text.substr(pos - 1);
            buf = buf.substr(buf.length() - 1,1);
            return(text);
        }
    }

    // 保留テーブルを検索する。
    if (keepTable.find(buf) != keepTable.end()) return(text);
    // テーブルを検索して入力する。
    map<String,WideString>::iterator it = RomkanTable.find(buf);
    if (it != RomkanTable.end()) {
        text = text.substr(0,pos - buf.length()) + it->second + text.substr(pos);
        pos = pos - buf.length() + it->second.length();
        buf.clear();
        return(text);
    }
    if (buf.length()) {
        buf = buf.substr(1);
        return(eval());
    }

    return(text);
}




/*!
    \fn Romkan::reset()
 */
void Romkan::reset()
{
    clear();
    pos = 0;
    mode = ROMA;
}

/*!
    \fn PreEditor::setText(const WideString &t)
 */
void Romkan::setText(const WideString &t)
{
    text = t;
    buf.clear();
}


/*!
    \fn Romkan::getText(bool hosei)
 */
WideString Romkan::getText(bool hosei)
{
    if (hosei) {
        if (buf.length()) {
            if (buf.substr(buf.length() - 1,1) == "n") {
                text = text.substr(0,pos - 1) + convChars[KANA_N];
            }
        }
    }
    return(text);
}


/*!
    \fn Romkan::backspace()
 */
void Romkan::backspace()
{
    if (getPos() == 0) return;
    text = text.substr(0,pos - 1) + text.substr(pos);
    setPos(pos - 1);
    // BSは小バッファもBSするゾ。
    if (buf.length()) buf = buf.substr(0,buf.length() - 1);
}



/*!
    \fn Romkan::del()
 */
void Romkan::del()
{
    if (getPos() == getTextLength()) return;
    text = text.substr(0,pos) + text.substr(pos + 1);
}



/*!
    \fn Romkan::hiraKata()
 */
void Romkan::hiraKata()
{
    convHiraKata(text);
}


/*!
    \fn Romkan::kataHira()
 */
void Romkan::kataHira()
{
    convKataHira(text);
}

/*!
    \fn Romkan::toHalf()
 */
void Romkan::toHalf()
{
    int p = getPos();
    convZenHan(text,p);
    if (p != getPos()) setPos(p);
    buf.clear();
}

/*!
    \fn Romkan::toWide()
 */
void Romkan::toWide()
{
    int p = getPos();
    convHanZen(text,pos);
    if (p != getPos()) setPos(p);
    buf.clear();
}



/*!
    \fn Romkan::keyEventHook(const KeyEvent &key)
 */
bool Romkan::keyEventHook(const KeyEvent &key)
{
    if ((isprint(key.code)) && ((mode == ASCII) || (mode == WASCII))) {
        if ((!key.is_alt_down()) && (!key.is_control_down())) {
            insert(key.get_ascii_code());
            return(true);
        }
    }

    if (!buf.length()) return(false);
    if (buf[buf.length() - 1] == 'Z') {
        if (key.code == SCIM_KEY_space) {
            insert(' ');
            return(true);
        }
    }
    return(false);
}


/*!
    \fn Romkan::getModeName()
 */
String Romkan::getModeName()
{
    switch(mode) {
        case ROMA: {
            return(String(_("Roma-Kana")));
            break;
        }
        case ASCII: {
            return(String(_("Ascii")));
            break;
        }
        case WASCII: {
            return(String(_("Wide Ascii")));
            break;
        }
    }
}


/*!
    \fn Romkan::cancelEvent()
 */
bool Romkan::cancelEvent()
{
    if ((mode == ASCII) || (mode == WASCII)) {
        mode = ROMA;
        return(true);
    }
    return(false);
}


/*!
    \fn Romkan::inputEvent(const KeyEvent &key)
 */
bool Romkan::inputEvent(const KeyEvent &key)
{
    // 喰っておくべきもの。
    if ((key.code == SCIM_KEY_Shift_L) ||
        (key.code == SCIM_KEY_Shift_R) ||
        (key.code == SCIM_KEY_Control_L) ||
        (key.code == SCIM_KEY_Control_R) ||
        (key.code == SCIM_KEY_Alt_L) ||
        (key.code == SCIM_KEY_Alt_R) ||
        (key.code == SCIM_KEY_Super_L) ||
        (key.code == SCIM_KEY_Super_R) ||
        (key.code == SCIM_KEY_Hyper_L) ||
        (key.code == SCIM_KEY_Hyper_R)) return(true);
    if (key_ascii_mode.comp(key)) {
        mode = ASCII;
        return(true);
    }
    if (key_wascii_mode.comp(key)) {
        mode = WASCII;
        return(true);
    }

    if (key.get_ascii_code() && (!key.is_alt_down()) && (!key.is_control_down())) {
        if (key.get_ascii_code() == ' ') return(false);
        // 素直に返すべきもの
        if ((key.code == SCIM_KEY_Return) ||
            (key.code == SCIM_KEY_Linefeed) ||
            (key.code == SCIM_KEY_Tab)) return(false);
        insert(key.get_ascii_code());
        return(true);
    }
    return(false);
}


/*!
    \fn Romkan::getName()
 */
String Romkan::getName()
{
    return(String(_("Roma")));
}