/* * Smart Common Input Method * * Copyright (c) 2002-2005 James Su * * * 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 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 program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * * $Id: scim_setup_ui.cpp,v 1.52.2.1 2007/05/04 02:17:36 juhp Exp $ * */ #include #include #define Uses_SCIM_COMPOSE_KEY #define Uses_SCIM_CONFIG_BASE #define Uses_SCIM_CONFIG_PATH #define Uses_SCIM_MODULE #define Uses_SCIM_IMENGINE_MODULE #define Uses_SCIM_HELPER #include "scim_private.h" #include "scim.h" #include "scim_setup_module.h" #include "scim_setup_ui.h" #define LIST_ICON_SIZE 20 #define SCIM_TRADEMARK_ICON_FILE (SCIM_ICONDIR "/trademark.png") const gchar * scim_setup_module_categories [] = { N_("SCIM"), N_("FrontEnd"), N_("IMEngine"), N_("Panel"), N_("Extra"), NULL }; enum { MODULE_LIST_LABEL = 0, MODULE_LIST_CATEGORY, MODULE_LIST_MODULE, MODULE_LIST_WIDGET, MODULE_LIST_NUM_COLUMNS }; SetupUI::SetupUI (const ConfigPointer &config, const String &display, const HelperInfo &helper_info) : m_main_window (0), m_work_area (0), m_apply_button (0), m_restore_button (0), m_status_bar (0), m_module_list_view (0), m_module_list_selection (0), m_module_list_model (0), m_current_widget (0), m_current_module (0), m_config (config), m_query_changed_timeout (0), m_changes_applied (false) { char **argv = new char * [4]; int argc = 1; argv [0] = "scim-setup"; argv [1] = 0; if (display.length ()) { argv [argc ++] = "--display"; argv [argc ++] = const_cast (display.c_str ()); argv [argc] = 0; setenv ("DISPLAY", display.c_str (), 1); } gtk_init (&argc, &argv); create_main_ui (); create_module_list_model (); m_query_changed_timeout = gtk_timeout_add (200, query_changed_timeout_cb, this); m_helper_agent.open_connection (helper_info, display); delete [] argv; } SetupUI::~SetupUI () { g_source_remove (m_query_changed_timeout); gtk_widget_destroy (m_main_window); m_helper_agent.close_connection (); } bool SetupUI::add_module (SetupModule *module) { if (!module || !module->valid ()) return false; GtkTreeIter iter, parent; GtkWidget *module_widget = module->create_ui (); String module_label = module->get_name (); String module_category = module->get_category (); if (!module_widget || !module_label.length () || !module_category.length ()) return false; if (!m_config.null ()) module->load_config (m_config); gtk_box_pack_start (GTK_BOX (m_work_area), module_widget, TRUE, TRUE, 0); gtk_widget_hide (module_widget); if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (m_module_list_model), &parent)) { gchar *category; do { gtk_tree_model_get (GTK_TREE_MODEL (m_module_list_model), &parent, MODULE_LIST_CATEGORY, &category, -1); // Find the right category and append the module. if (category && !strcmp (category, module_category.c_str ())) { gtk_tree_store_append (m_module_list_model, &iter, &parent); gtk_tree_store_set ( m_module_list_model, &iter, MODULE_LIST_LABEL, module_label.c_str (), MODULE_LIST_CATEGORY, NULL, MODULE_LIST_MODULE, module, MODULE_LIST_WIDGET, module_widget, -1); g_free (category); gtk_tree_view_expand_all (GTK_TREE_VIEW (m_module_list_view)); return true; } g_free (category); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (m_module_list_model), &parent)); } GtkWidget *cover; cover = create_setup_cover (module_category.c_str ()); gtk_box_pack_start (GTK_BOX (m_work_area), cover, TRUE, TRUE, 0); // No suitable category available, add one. gtk_tree_store_append (m_module_list_model, &parent, NULL); gtk_tree_store_set ( m_module_list_model, &parent, MODULE_LIST_LABEL, _(module_category.c_str ()), MODULE_LIST_CATEGORY, module_category.c_str (), MODULE_LIST_MODULE, NULL, MODULE_LIST_WIDGET, cover, -1); gtk_tree_store_append (m_module_list_model, &iter, &parent); gtk_tree_store_set ( m_module_list_model, &iter, MODULE_LIST_LABEL, module_label.c_str (), MODULE_LIST_CATEGORY, NULL, MODULE_LIST_MODULE, module, MODULE_LIST_WIDGET, module_widget, -1); gtk_tree_view_expand_all (GTK_TREE_VIEW (m_module_list_view)); return true; } void SetupUI::run () { SCIM_DEBUG_MAIN(1) << "SetupUI::run ()\n"; if (m_main_window) { gtk_widget_show (m_main_window); gtk_main (); } if (m_changes_applied) { // Flush the global config before sending reload config event. scim_global_config_flush (); m_helper_agent.reload_config (); } SCIM_DEBUG_MAIN(1) << "exit SetupUI::run ()\n"; } void SetupUI::create_main_ui () { GtkWidget *hpaned1; GtkWidget *scrolledwindow1; GtkWidget *vbox1; GtkWidget *vbox2; GtkWidget *frame1; GtkWidget *hbox1; GtkWidget *ok_button; GtkWidget *exit_button; GtkWidget *vseparator1; GdkPixbuf *icon; GtkCellRenderer *module_list_cell; GtkTreeViewColumn *module_list_column; // Create main window. m_main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (m_main_window), _("SCIM Input Method Setup")); gtk_window_set_position (GTK_WINDOW (m_main_window), GTK_WIN_POS_CENTER); gtk_window_set_modal (GTK_WINDOW (m_main_window), TRUE); gtk_window_set_destroy_with_parent (GTK_WINDOW (m_main_window), TRUE); gtk_window_set_resizable (GTK_WINDOW (m_main_window), TRUE); // Set the window icon icon = gdk_pixbuf_new_from_file (SCIM_TRADEMARK_ICON_FILE, NULL); if (icon) { gtk_window_set_icon (GTK_WINDOW (m_main_window), icon); g_object_unref (icon); } vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (m_main_window), vbox1); // Create paned window. hpaned1 = gtk_hpaned_new (); gtk_widget_show (hpaned1); gtk_box_pack_start (GTK_BOX (vbox1), hpaned1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hpaned1), 4); // Create statusbar. m_status_bar = gtk_statusbar_new (); gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (m_status_bar), TRUE); gtk_widget_show (m_status_bar); gtk_box_pack_start (GTK_BOX (vbox1), m_status_bar, FALSE, FALSE, 0); // Create scrollwindow for module list. scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow1); gtk_paned_pack1 (GTK_PANED (hpaned1), scrolledwindow1, FALSE, FALSE); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_ETCHED_IN); // Create module list view. m_module_list_view = gtk_tree_view_new (); gtk_widget_show (m_module_list_view); gtk_container_add (GTK_CONTAINER (scrolledwindow1), m_module_list_view); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (m_module_list_view), FALSE); gtk_tree_view_set_enable_search (GTK_TREE_VIEW (m_module_list_view), FALSE); // Get module list selection. m_module_list_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (m_module_list_view)); gtk_tree_selection_set_mode (m_module_list_selection, GTK_SELECTION_BROWSE); // Create module list column. module_list_cell = gtk_cell_renderer_text_new (); module_list_column = gtk_tree_view_column_new_with_attributes ( NULL, module_list_cell, "text", MODULE_LIST_LABEL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (m_module_list_view), module_list_column); // Create vbox for work area and button area. vbox2 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox2); gtk_paned_pack2 (GTK_PANED (hpaned1), vbox2, TRUE, FALSE); // Create frame for work area. frame1 = gtk_frame_new (NULL); gtk_widget_show (frame1); gtk_box_pack_start (GTK_BOX (vbox2), frame1, TRUE, TRUE, 0); m_work_area = gtk_vbox_new (FALSE, 0); gtk_widget_show (m_work_area); gtk_container_add (GTK_CONTAINER (frame1), m_work_area); // Create hbox for button area. hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); gtk_box_pack_end (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 8); ok_button = gtk_button_new_from_stock ("gtk-ok"); gtk_widget_show (ok_button); gtk_box_pack_end (GTK_BOX (hbox1), ok_button, FALSE, FALSE, 4); exit_button = gtk_button_new_from_stock ("gtk-quit"); gtk_widget_show (exit_button); gtk_box_pack_end (GTK_BOX (hbox1), exit_button, FALSE, FALSE, 4); vseparator1 = gtk_vseparator_new (); gtk_widget_show (vseparator1); gtk_box_pack_end (GTK_BOX (hbox1), vseparator1, FALSE, FALSE, 4); m_apply_button = gtk_button_new_from_stock ("gtk-apply"); gtk_widget_show (m_apply_button); gtk_box_pack_end (GTK_BOX (hbox1), m_apply_button, FALSE, FALSE, 4); GTK_WIDGET_SET_FLAGS (m_apply_button, GTK_CAN_DEFAULT); gtk_widget_set_sensitive (m_apply_button, FALSE); m_restore_button = gtk_button_new_from_stock ("gtk-revert-to-saved"); gtk_widget_show (m_restore_button); gtk_box_pack_end (GTK_BOX (hbox1), m_restore_button, FALSE, FALSE, 4); gtk_widget_set_sensitive (m_restore_button, FALSE); g_signal_connect ((gpointer) ok_button, "clicked", G_CALLBACK (SetupUI::ok_button_clicked_callback), this); g_signal_connect ((gpointer) exit_button, "clicked", G_CALLBACK (SetupUI::exit_button_clicked_callback), this); g_signal_connect ((gpointer) m_apply_button, "clicked", G_CALLBACK (SetupUI::apply_button_clicked_callback), this); g_signal_connect ((gpointer) m_restore_button, "clicked", G_CALLBACK (SetupUI::restore_button_clicked_callback), this); g_signal_connect (G_OBJECT (m_main_window), "delete_event", G_CALLBACK (main_window_delete_callback), this); g_signal_connect (G_OBJECT (m_module_list_selection), "changed", G_CALLBACK (module_list_selection_changed_callback), this); gtk_widget_grab_default (m_apply_button); } GtkWidget * SetupUI::create_splash_view () { GtkRequisition size; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *view; GtkWidget *combo; GtkWidget *label; GtkWidget *separator; vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox); view = gtk_label_new (NULL); gtk_widget_show (view); gtk_label_set_justify (GTK_LABEL (view), GTK_JUSTIFY_CENTER); gtk_label_set_markup (GTK_LABEL (view), _( " Smart Common Input Method platform \n\n" "GUI Setup Utility\n\n\n\n" "Copyright 2002-2004, James Su <suzhe@tsinghua.org.cn>")); gtk_box_pack_start (GTK_BOX (vbox), view, TRUE, TRUE, 4); gtk_widget_size_request (vbox, &size); if (size.width < 320) size.width = 320; if (size.height < 240) size.height = 240; gtk_widget_set_size_request (vbox, size.width, size.height); gtk_widget_hide (vbox); return vbox; } GtkWidget * SetupUI::create_setup_cover (const char *category) { GtkRequisition size; GtkWidget *cover; char buf [128]; snprintf (buf, 127, _("The Setup for %s modules."), _(category)); cover = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (cover), buf); gtk_label_set_justify (GTK_LABEL (cover), GTK_JUSTIFY_CENTER); gtk_widget_show (cover); gtk_widget_size_request (cover, &size); if (size.width < 320) size.width = 320; if (size.height < 240) size.height = 240; gtk_widget_set_size_request (cover, size.width, size.height); gtk_widget_hide (cover); return cover; } void SetupUI::create_module_list_model () { GtkTreeIter iter; GtkWidget *widget; widget = create_splash_view (); gtk_box_pack_start (GTK_BOX (m_work_area), widget, TRUE, TRUE, 0); m_module_list_model = gtk_tree_store_new ( MODULE_LIST_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, GTK_TYPE_WIDGET); gtk_tree_store_append (m_module_list_model, &iter, NULL); gtk_tree_store_set (m_module_list_model, &iter, MODULE_LIST_LABEL, _(scim_setup_module_categories [0]), MODULE_LIST_CATEGORY, scim_setup_module_categories [0], MODULE_LIST_MODULE, NULL, MODULE_LIST_WIDGET, widget, -1); gtk_tree_view_set_model (GTK_TREE_VIEW (m_module_list_view), GTK_TREE_MODEL (m_module_list_model)); } bool SetupUI::ask_quit () const { GtkWidget *dialog; gint result; dialog = gtk_message_dialog_new (GTK_WINDOW (m_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, _("Are you sure you want to quit SCIM Setup?")); result = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return result == GTK_RESPONSE_OK; } gboolean SetupUI::module_list_hide_widget_iter_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GtkWidget *widget; gtk_tree_model_get (model, iter, MODULE_LIST_WIDGET, &widget, -1); if (widget) gtk_widget_hide (widget); g_object_unref (widget); return FALSE; } void SetupUI::module_list_selection_changed_callback (GtkTreeSelection *selection, gpointer user_data) { GtkTreeModel *model; GtkTreeIter iter; GtkWidget *widget; SetupModule *module; gchar *label; gchar *category; SetupUI * ui = (SetupUI *) user_data; if (gtk_tree_selection_get_selected (selection, &model, &iter)) { gtk_tree_model_get (model, &iter, MODULE_LIST_LABEL, &label, MODULE_LIST_CATEGORY, &category, MODULE_LIST_MODULE, &module, MODULE_LIST_WIDGET, &widget, -1); if (widget != ui->m_current_widget) { //Hide all other widgets gtk_tree_model_foreach (model, module_list_hide_widget_iter_func, NULL); gtk_widget_show (widget); ui->m_current_widget = widget; } if (module != ui->m_current_module || !module) { gtk_statusbar_pop (GTK_STATUSBAR (ui->m_status_bar), 1); gtk_widget_set_sensitive (ui->m_apply_button, FALSE); gtk_widget_set_sensitive (ui->m_restore_button, FALSE); if (module) { String desc = module->get_description (); if (desc.length ()) gtk_statusbar_push (GTK_STATUSBAR (ui->m_status_bar), 1, desc.c_str ()); if (module->query_changed () && !ui->m_config.null ()) { gtk_widget_set_sensitive (ui->m_apply_button, TRUE); gtk_widget_set_sensitive (ui->m_restore_button, TRUE); } } ui->m_current_module = module; } g_free (label); if (category) g_free (category); g_object_unref (widget); } } void SetupUI::restore_button_clicked_callback (GtkButton *button, gpointer user_data) { SetupUI *ui = (SetupUI*) user_data; if (ui->m_config.null ()) return; if (ui->m_current_module) { ui->m_current_module->load_config (ui->m_config); gtk_widget_set_sensitive (ui->m_apply_button, FALSE); gtk_widget_set_sensitive (ui->m_restore_button, FALSE); } } void SetupUI::apply_button_clicked_callback (GtkButton *button, gpointer user_data) { SetupUI *ui = (SetupUI*) user_data; if (ui->m_config.null ()) return; if (ui->m_current_module) { ui->m_current_module->save_config (ui->m_config); ui->m_config->flush (); ui->m_changes_applied = true; gtk_widget_set_sensitive (ui->m_apply_button, FALSE); gtk_widget_set_sensitive (ui->m_restore_button, FALSE); } } gboolean SetupUI::module_list_save_config_iter_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { SetupModule *module; SetupUI *ui = (SetupUI *) data; gtk_tree_model_get (model, iter, MODULE_LIST_MODULE, &module, -1); if (module && module->query_changed () && ui && !ui->m_config.null ()) { module->save_config (ui->m_config); ui->m_changes_applied = true; } return FALSE; } gboolean SetupUI::module_list_load_config_iter_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { SetupModule *module; SetupUI *ui = (SetupUI *) data; gtk_tree_model_get (model, iter, MODULE_LIST_MODULE, &module, -1); if (module && ui && !ui->m_config.null ()) module->load_config (ui->m_config); return FALSE; } void SetupUI::ok_button_clicked_callback (GtkButton *button, gpointer user_data) { SetupUI *ui = (SetupUI *) user_data; if (!ui->m_config.null ()) { gtk_tree_model_foreach (GTK_TREE_MODEL (ui->m_module_list_model), module_list_save_config_iter_func, user_data); ui->m_config->flush (); if (ui->m_changes_applied) ui->show_restart_hint (); } gtk_main_quit (); } void SetupUI::exit_button_clicked_callback (GtkButton *button, gpointer user_data) { SetupUI *ui = (SetupUI*) user_data; if (ui->ask_quit ()) { if (ui->m_changes_applied) ui->show_restart_hint (); gtk_main_quit (); } } gboolean SetupUI::main_window_delete_callback (GtkWidget *widget, GdkEvent *event, gpointer user_data) { SetupUI *ui = (SetupUI*) user_data; if (ui->ask_quit ()) { if (ui->m_changes_applied) ui->show_restart_hint (); gtk_main_quit (); } return TRUE; } gboolean SetupUI::query_changed_timeout_cb (gpointer data) { SetupUI *ui = (SetupUI *) data; if (ui->m_helper_agent.has_pending_event ()) ui->m_helper_agent.filter_event (); bool modified = false; if (!ui->m_config.null () && ui->m_config->valid () && ui->m_current_module && ui->m_current_module->query_changed ()) modified = true; if (GTK_WIDGET_SENSITIVE (ui->m_apply_button) != modified) gtk_widget_set_sensitive (ui->m_apply_button, modified); if (GTK_WIDGET_SENSITIVE (ui->m_restore_button) != modified) gtk_widget_set_sensitive (ui->m_restore_button, modified); return TRUE; } void SetupUI::show_restart_hint () const { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (m_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("Not all configuration can be reloaded on the fly. " "Don't forget to restart SCIM in order to let all of " "the new configuration take effect.")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } /* vi:ts=4:nowrap:ai:expandtab */