Newer
Older
scim-wnn / scim-wnn / src / scim_wnn_imengine_setup.cpp
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 *  Copyright (C) 2004 TAM (Teppei Tamra)
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *  Copyright (C) 2004 Takuro Ashie
 *
 *  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, 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.
 */

/*
 * Based on scim-hangul.
 * Copyright (c) 2004 James Su <suzhe@turbolinux.com.cn>
 */

#define Uses_SCIM_CONFIG_BASE

#include <gtk/gtk.h>

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

#include <scim.h>
#include <gtk/scimkeyselection.h>
#include "scim_wnn_def.h"

#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

using namespace scim;

#define scim_module_init wnn_imengine_setup_LTX_scim_module_init
#define scim_module_exit wnn_imengine_setup_LTX_scim_module_exit

#define scim_setup_module_create_ui       wnn_imengine_setup_LTX_scim_setup_module_create_ui
#define scim_setup_module_get_category    wnn_imengine_setup_LTX_scim_setup_module_get_category
#define scim_setup_module_get_name        wnn_imengine_setup_LTX_scim_setup_module_get_name
#define scim_setup_module_get_description wnn_imengine_setup_LTX_scim_setup_module_get_description
#define scim_setup_module_load_config     wnn_imengine_setup_LTX_scim_setup_module_load_config
#define scim_setup_module_save_config     wnn_imengine_setup_LTX_scim_setup_module_save_config
#define scim_setup_module_query_changed   wnn_imengine_setup_LTX_scim_setup_module_query_changed



static GtkWidget * create_setup_window ();
static void        load_config (const ConfigPointer &config);
static void        save_config (const ConfigPointer &config);
static bool        query_changed ();

// Module Interface.
/*
    ****今回のリリースでは設定モジュールは搭載させません****

    !!!リリース後コメントアウトを外してデバグ!!!
*/

extern "C" {
    void scim_module_init (void)
    {
        bindtextdomain (GETTEXT_PACKAGE, SCIM_WNN_LOCALEDIR);
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
    }

    void scim_module_exit (void)
    {
    }

    GtkWidget * scim_setup_module_create_ui (void)
    {
        return create_setup_window ();
    }

    String scim_setup_module_get_category (void)
    {
        return String ("IMEngine");
    }

    String scim_setup_module_get_name (void)
    {
        return String (_("Wnn"));
    }

    String scim_setup_module_get_description (void)
    {
        return String (_("A Wnn IMEngine Module."));
    }

    void scim_setup_module_load_config (const ConfigPointer &config)
    {
        load_config (config);
    }

    void scim_setup_module_save_config (const ConfigPointer &config)
    {
        save_config (config);
    }

    bool scim_setup_module_query_changed ()
    {
        return query_changed ();
    }
} // extern "C"


// Internal data structure
struct KeyboardConfigData
{
    const char *key;
    String      data;
    const char *label;
    const char *title;
    const char *tooltip;
    GtkWidget  *entry;
    GtkWidget  *button;
};

struct KeyboardConfigPage
{
    const char         *label;
    KeyboardConfigData *data;
};

// Internal data declaration.
//static bool __config_use_kana = false;
static String __config_server = SCIM_DEFAULT_WNN_SERVER;
static String __config_wnn_rc = SCIM_DEFAULT_WNN_RC;

static bool __have_changed    = true;

//static GtkWidget    * __widget_use_kana = 0;
static GtkWidget    * __widget_server = 0;
static GtkWidget    * __widget_wnn_rc = 0;
static GtkTooltips  * __widget_tooltips = 0;

static KeyboardConfigData __config_keyboards_common [] =
{
    {
        SCIM_CONFIG_WNN_KEY_COMMIT,
        SCIM_DEFAULT_WNN_KEY_COMMIT,
        N_("Commit keys:"),
        N_("Select commit keys"),
        N_("The key events to commit the preedit string. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_START,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_START,
        N_("Convert keys:"),
        N_("Select convert keys"),
        N_("The key events to convert the preedit string to kanji. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CANCEL,
        SCIM_DEFAULT_WNN_KEY_CANCEL,
        N_("Cancel keys:"),
        N_("Select cancel keys"),
        N_("The key events to cancel preediting or converting. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_BACKSPACE,
        SCIM_DEFAULT_WNN_KEY_BACKSPACE,
        N_("Backspace keys:"),
        N_("Select backspace keys"),
        N_("The key events to delete a character before caret. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_DELETE,
        SCIM_DEFAULT_WNN_KEY_DELETE,
        N_("Delete keys:"),
        N_("Select delete keys"),
        N_("The key events to delete a character after caret. "),
        NULL,
        NULL,
    },
    {
        NULL,
        "",
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
    },
};

static KeyboardConfigData __config_keyboards_caret [] =
{
    {
        SCIM_CONFIG_WNN_KEY_FORWARD,
        SCIM_DEFAULT_WNN_KEY_FORWARD,
        N_("Move forward keys:"),
        N_("Select move caret forward keys"),
        N_("The key events to move the caret to forward. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_BACKWARD,
        SCIM_DEFAULT_WNN_KEY_BACKWARD,
        N_("Move backward keys:"),
        N_("Select move caret backward keys"),
        N_("The key events to move the caret to backward. "),
        NULL,
        NULL,
    },
    {
        NULL,
        "",
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
    },
};

static KeyboardConfigData __config_keyboards_segment [] =
{
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_FORWARD,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_FORWARD,
        N_("Next segment keys:"),
        N_("Select next segment keys"),
        N_("The key events to select next segment. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_BACKWARD,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_BACKWARD,
        N_("Previous segment keys:"),
        N_("Select previous segment keys"),
        N_("The key events to select previous segment. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_SHRINK,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_SHRINK,
        N_("Shrink segment keys:"),
        N_("Select shrink segment keys"),
        N_("The key events to shrink the selected segment. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_EXPAND,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_EXPAND,
        N_("Expand segment keys:"),
        N_("Select expand segment keys"),
        N_("The key events to expand the selected segment. "),
        NULL,
        NULL,
    },
    {
        NULL,
        "",
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
    },
};

static KeyboardConfigData __config_keyboards_candidates [] =
{
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_NEXT,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_NEXT,
        N_("Next keys:"),
        N_("Select next candidate keys"),
        N_("The key events to select next candidate. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_CONVERSION_PREV,
        SCIM_DEFAULT_WNN_KEY_CONVERSION_PREV,
        N_("Previous keys:"),
        N_("Select previous candidate keys"),
        N_("The key events to select previous candidate. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_LOOKUPPAGEUP,
        SCIM_DEFAULT_WNN_KEY_LOOKUPPAGEUP,
        N_("Page up keys:"),
        N_("Select page up candidates keys"),
        N_("The key events to select page up candidates. "),
        NULL,
        NULL,
    },
    {
        SCIM_CONFIG_WNN_KEY_LOOKUPPAGEDOWN,
        SCIM_DEFAULT_WNN_KEY_LOOKUPPAGEDOWN,
        N_("Page down keys:"),
        N_("Select page down candidates keys"),
        N_("The key events to select page down candidates. "),
        NULL,
        NULL,
    },
    {
        NULL,
        "",
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
    },
};

static struct KeyboardConfigPage __key_conf_pages[] =
{
    {N_("Common keys"),     __config_keyboards_common},
    {N_("Preedit keys"),    __config_keyboards_caret},
    {N_("Candidates keys"), __config_keyboards_candidates},
};
static unsigned int __key_conf_pages_num = sizeof (__key_conf_pages) / sizeof (KeyboardConfigPage);

static void on_default_editable_changed      (GtkEditable *editable,
                                              gpointer     user_data);
/*
static void on_default_toggle_button_toggled (GtkToggleButton *togglebutton,
                                              gpointer         user_data);
*/
static void on_default_key_selection_clicked (GtkButton *button,
                                              gpointer   user_data);
static void on_default_file_selection_button (GtkButton *button,
                                              gpointer user_data);
static void setup_widget_value (void);


static GtkWidget *
create_options_page ()
{
    GtkWidget *vbox, *table, *label, *button;

    vbox = gtk_vbox_new (FALSE, 0);
    gtk_widget_show (vbox);

    //__widget_use_kana = gtk_check_button_new_with_mnemonic (_("Use _Kana Table"));
    //gtk_widget_show (__widget_use_kana);
    //gtk_box_pack_start (GTK_BOX (vbox), __widget_use_kana, FALSE, FALSE, 4);
    //gtk_container_set_border_width (GTK_CONTAINER (__widget_use_kana), 4);

    // Connect all signals.
    //g_signal_connect ((gpointer) __widget_use_kana, "toggled",
    //                  G_CALLBACK (on_default_toggle_button_toggled),
    //                  &__config_use_kana);

    table = gtk_table_new (3, 3, FALSE);
    gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
    gtk_widget_show (table);

    /* server */
    label = gtk_label_new_with_mnemonic (_("_Server: "));
    gtk_widget_show (label);
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_misc_set_padding (GTK_MISC (label), 4, 0);
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (GTK_FILL), 4, 4);

    __widget_server = gtk_entry_new ();
    gtk_widget_show (__widget_server);
    gtk_table_attach (GTK_TABLE (table), __widget_server, 1, 2, 0, 1,
                      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
                      (GtkAttachOptions) (GTK_FILL), 4, 4);
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), __widget_server);

    /* wnnenvrc */
    label = gtk_label_new_with_mnemonic (_("_wnnenvrc: "));
    gtk_widget_show (label);
    gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
    gtk_misc_set_padding (GTK_MISC (label), 4, 0);
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (GTK_FILL), 4, 4);

    __widget_wnn_rc = gtk_entry_new ();
    gtk_widget_show (__widget_wnn_rc);
    gtk_table_attach (GTK_TABLE (table), __widget_wnn_rc, 1, 2, 1, 2,
                      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
                      (GtkAttachOptions) (GTK_FILL), 4, 4);
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), __widget_wnn_rc);

    button = gtk_button_new_with_label (_("..."));
    gtk_widget_show (button);
    gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (GTK_FILL), 4, 4);
    //gtk_label_set_mnemonic_widget (GTK_LABEL (label), button);

    /* connect all signals */
    g_signal_connect ((gpointer) __widget_server, "changed",
                      G_CALLBACK (on_default_editable_changed),
                      &__config_server);
    g_signal_connect ((gpointer) __widget_wnn_rc, "changed",
                      G_CALLBACK (on_default_editable_changed),
                      &__config_wnn_rc);
    g_signal_connect ((gpointer) button, "clicked",
                      G_CALLBACK (on_default_file_selection_button),
                      __widget_wnn_rc);

    return vbox;
}

static GtkWidget *
create_keyboard_page (unsigned int page)
{
    GtkWidget *table;
    GtkWidget *label;

    if (page >= __key_conf_pages_num)
        return NULL;

    KeyboardConfigData *data = __key_conf_pages[page].data;

    table = gtk_table_new (3, 3, FALSE);
    gtk_widget_show (table);

    // Create keyboard setting.
    for (unsigned int i = 0; data[i].key; ++ i) {
        label = gtk_label_new (NULL);
        gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _(data[i].label));
        gtk_widget_show (label);
        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
        gtk_misc_set_padding (GTK_MISC (label), 4, 0);
        gtk_table_attach (GTK_TABLE (table), label, 0, 1, i, i+1,
                          (GtkAttachOptions) (GTK_FILL),
                          (GtkAttachOptions) (GTK_FILL), 4, 4);

        data[i].entry = gtk_entry_new ();
        gtk_widget_show (data[i].entry);
        gtk_table_attach (GTK_TABLE (table), data[i].entry, 1, 2, i, i+1,
                          (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
                          (GtkAttachOptions) (GTK_FILL), 4, 4);
        gtk_entry_set_editable (GTK_ENTRY (data[i].entry), FALSE);

        data[i].button = gtk_button_new_with_label (_("..."));
        gtk_widget_show (data[i].button);
        gtk_table_attach (GTK_TABLE (table), data[i].button, 2, 3, i, i+1,
                          (GtkAttachOptions) (GTK_FILL),
                          (GtkAttachOptions) (GTK_FILL), 4, 4);
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), data[i].button);
    }

    for (unsigned int i = 0; data[i].key; ++ i) {
        g_signal_connect ((gpointer) data[i].button, "clicked",
                          G_CALLBACK (on_default_key_selection_clicked),
                          &(data[i]));
        g_signal_connect ((gpointer) data[i].entry, "changed",
                          G_CALLBACK (on_default_editable_changed),
                          &(data[i].data));
    }

    if (!__widget_tooltips)
        __widget_tooltips = gtk_tooltips_new();
    for (unsigned int i = 0; data[i].key; ++ i) {
        gtk_tooltips_set_tip (__widget_tooltips, data[i].entry,
                              _(data[i].tooltip), NULL);
    }

    return table;
}

static GtkWidget *
create_setup_window ()
{
    static GtkWidget *window = NULL;

    if (!window) {
        GtkWidget *notebook = gtk_notebook_new();
        gtk_widget_show (notebook);
        window = notebook;
        gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);

        // Create the first page.
        GtkWidget *page = create_options_page ();
        GtkWidget *label = gtk_label_new (_("Options"));
        gtk_widget_show (label);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);

        setup_widget_value ();

        // Create the second page.
        for (unsigned int i = 0; i < __key_conf_pages_num; i++) {
            page = create_keyboard_page (i);
            label = gtk_label_new (_(__key_conf_pages[i].label));
            gtk_widget_show (label);
            gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, label);
        }

        setup_widget_value ();
    }

    return window;
}

static void
setup_widget_value (void)
{
//    if (__widget_use_kana) {
//        gtk_toggle_button_set_active (
//            GTK_TOGGLE_BUTTON (__widget_use_kana),
//            __config_use_kana);
//    }
    if (__widget_server) {
        gtk_entry_set_text (
            GTK_ENTRY (__widget_server),
            __config_server.c_str ());
    }

    if (__widget_wnn_rc) {
        gtk_entry_set_text (
            GTK_ENTRY (__widget_wnn_rc),
            __config_wnn_rc.c_str ());
    }

    for (unsigned int j = 0; j < __key_conf_pages_num; ++ j) {
        for (unsigned int i = 0; __key_conf_pages[j].data[i].key; ++ i) {
            if (__key_conf_pages[j].data[i].entry) {
                gtk_entry_set_text (
                    GTK_ENTRY (__key_conf_pages[j].data[i].entry),
                    __key_conf_pages[j].data[i].data.c_str ());
            }
        }
    }
}

static void
load_config (const ConfigPointer &config)
{
    if (!config.null ()) {
    //    __config_use_kana =
    //        config->read (String (SCIM_CONFIG_IMENGINE_ANTHY_USE_KANA),
    //                      __config_use_kana);
        __config_server =
            config->read (String (SCIM_CONFIG_WNN_SERVER),
                          __config_server);
        __config_wnn_rc =
            config->read (String (SCIM_CONFIG_WNN_RC),
                          __config_wnn_rc);

        for (unsigned int j = 0; j < __key_conf_pages_num; j++) {
            for (unsigned int i = 0; __key_conf_pages[j].data[i].key; ++ i) {
                __key_conf_pages[j].data[i].data =
                    config->read (String (__key_conf_pages[j].data[i].key),
                                  __key_conf_pages[j].data[i].data);
            }
        }

        setup_widget_value ();

        __have_changed = false;
    }
}

static void
save_config (const ConfigPointer &config)
{
    if (!config.null ()) {
    //    config->write (String (SCIM_CONFIG_IMENGINE_ANTHY_USE_KANA),
    //                    __config_use_kana);
        config->write (String (SCIM_CONFIG_WNN_SERVER),
                       __config_server);
        config->write (String (SCIM_CONFIG_WNN_RC),
                       __config_wnn_rc);

        for (unsigned j = 0; j < __key_conf_pages_num; j++) {
            for (unsigned int i = 0; __key_conf_pages[j].data[i].key; ++ i) {
                config->write (String (__key_conf_pages[j].data[i].key),
                               __key_conf_pages[j].data[i].data);
            }
        }

        __have_changed = false;
    }
}

static bool
query_changed ()
{
    return __have_changed;
}


/*
static void
on_default_toggle_button_toggled (GtkToggleButton *togglebutton,
                                  gpointer         user_data)
{
    bool *toggle = static_cast<bool*> (user_data);

    if (toggle) {
        *toggle = gtk_toggle_button_get_active (togglebutton);
        __have_changed = true;
    }
}
*/

static void
on_default_editable_changed (GtkEditable *editable,
                             gpointer     user_data)
{
    String *str = static_cast <String *> (user_data);

    if (str) {
        *str = String (gtk_entry_get_text (GTK_ENTRY (editable)));
        __have_changed = true;
    }
}

static void
on_default_key_selection_clicked (GtkButton *button,
                                  gpointer   user_data)
{
    KeyboardConfigData *data = static_cast <KeyboardConfigData *> (user_data);

    if (data) {
        GtkWidget *dialog = scim_key_selection_dialog_new (_(data->title));
        gint result;

        scim_key_selection_dialog_set_keys (
            SCIM_KEY_SELECTION_DIALOG (dialog),
            gtk_entry_get_text (GTK_ENTRY (data->entry)));

        result = gtk_dialog_run (GTK_DIALOG (dialog));

        if (result == GTK_RESPONSE_OK) {
            const gchar *keys = scim_key_selection_dialog_get_keys (
                            SCIM_KEY_SELECTION_DIALOG (dialog));

            if (!keys) keys = "";

            if (strcmp (keys, gtk_entry_get_text (GTK_ENTRY (data->entry))) != 0)
                gtk_entry_set_text (GTK_ENTRY (data->entry), keys);
        }

        gtk_widget_destroy (dialog);
    }
}

static void
on_ok_clicked (GtkButton *button, gpointer user_data)
{
    bool *ok = static_cast<bool*>(user_data);
    if (ok)
        *ok = true;
}

static void
on_default_file_selection_button (GtkButton *button, gpointer user_data)
{
    GtkEntry *entry = GTK_ENTRY (user_data);
    const char *path = gtk_entry_get_text (entry);
    bool ok = false;

    GtkFileSelection *sel = GTK_FILE_SELECTION (gtk_file_selection_new ("Select a file"));
    gtk_file_selection_set_filename (sel, path);
    g_signal_connect (G_OBJECT (sel->ok_button), "clicked",
                      G_CALLBACK (on_ok_clicked),
                      (gpointer) &ok);
    gtk_window_set_transient_for (
        GTK_WINDOW (sel),
        GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET (entry))));
    gtk_dialog_run (GTK_DIALOG (sel));

    if (ok)
        gtk_entry_set_text (entry, gtk_file_selection_get_filename (sel));

    gtk_widget_destroy (GTK_WIDGET (sel));
}