*** empty log message ***
authorntakahas <ntakahas>
Mon, 23 Apr 2007 05:40:24 +0000 (05:40 +0000)
committerntakahas <ntakahas>
Mon, 23 Apr 2007 05:40:24 +0000 (05:40 +0000)
src/command.c
src/mim-config.c
src/variable.c

index 1575c97..0751916 100644 (file)
@@ -1,22 +1,53 @@
 #include <stdlib.h>
 #include <string.h>
 #include <libintl.h>
+#include <m17n.h>
 #include <gtk/gtk.h>
 #include <gdk/gdk.h>
 #include <gdk/gdkkeysyms.h>
-#include <m17n.h>
+#include <config.h>
+
+#define _(String) dgettext (PACKAGE, String)
+
+#define CURRENT_BINDINGS       \
+  (mplist_next                 \
+   (mplist_next                        \
+    (mplist_next               \
+     (mplist_value             \
+      (minput_get_command      \
+       (current_lang, current_name, current_command))))))
+
+#define CURRENT_STATUS         \
+  (mplist_value                        \
+   (mplist_next                        \
+    (mplist_next               \
+     (mplist_value             \
+      (minput_get_command      \
+       (current_lang, current_name, current_command))))))
+
+#define CONFIG_COMMAND(plist)                                          \
+  minput_config_command (current_lang, current_name, current_command,  \
+                        (plist))
 
+static unsigned modifier_state = 0;
+static MPlist *entry_keyseq;
 static MSymbol current_lang, current_name, current_command;
 
-static MPlist *
-get_command_bindings (MSymbol lang, MSymbol name, MSymbol command)
+struct BindingWidgets
 {
-  return (mplist_next
-         (mplist_next
-          (mplist_next
-           (mplist_value
-            (minput_get_command (lang, name, command))))));
-}
+  GtkWidget *entry;
+  GtkWidget *clear;
+  GtkWidget *add;
+  GtkWidget *view;
+  GtkWidget *delete;
+};
+
+enum KeyMaskBit {
+  META_MASK_BIT = 1,
+  ALT_MASK_BIT = META_MASK_BIT << 1,
+  SUPER_MASK_BIT = ALT_MASK_BIT << 1,
+  HYPER_MASK_BIT = SUPER_MASK_BIT << 1
+};
 
 static int
 keyseq_equal (MPlist *pl1, MPlist *pl2)
@@ -34,95 +65,6 @@ keyseq_equal (MPlist *pl1, MPlist *pl2)
 }
 
 static void
-keyseq_render_function (GtkTreeViewColumn *column,
-                       GtkCellRenderer *renderer,
-                       GtkTreeModel *model,
-                       GtkTreeIter *iter,
-                       gpointer data)
-{
-  MPlist *keyseq, *pl;
-  gint n;
-  gchar buf[1024];
-
-  gtk_tree_model_get (model, iter, 0, &keyseq, -1);
-  for (pl = keyseq, n = 0;
-       pl && mplist_key (pl) == Msymbol;
-       pl = mplist_next (pl))
-    n += strlen (msymbol_name ((MSymbol) mplist_value (pl))) + 1;
-  if (n < sizeof (buf))
-    {
-      buf[0] = '\0';
-      for (pl = keyseq;
-          pl && mplist_key (pl) == Msymbol;
-          pl = mplist_next (pl))
-       {
-         strcat (buf, msymbol_name ((MSymbol) mplist_value (pl)));
-         strcat (buf, " ");
-       }
-      g_object_set (renderer, "foreground-set", FALSE, NULL);
-    }
-  else
-    {
-      g_snprintf (buf, sizeof (buf), "Too long to display");
-      g_object_set (renderer, "foreground", "Red", "foreground-set", TRUE,
-                   NULL);
-    }
-  g_object_set (renderer, "text", buf, NULL);
-}
-
-static void
-delete_cb (GtkButton *button, GtkWidget *view)
-{
-  GtkTreeSelection *selection;
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  MPlist *keyseq, *old, *new, *pl;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
-
-      old = get_command_bindings (current_lang, current_name, current_command);
-      new = mplist ();
-      for (pl = old; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
-       if (! keyseq_equal (mplist_value (pl), keyseq))
-         mplist_add (new, Mplist, mplist_value (pl));
-      minput_config_command (current_lang, current_name, current_command, new);
-      m17n_object_unref (new);
-      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-    }
-}
-  
-
-static void
-delete_keyseq (GtkWidget *view, MSymbol lang, MSymbol name, MSymbol command)
-{
-  GtkTreeSelection *selection;
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  MPlist *keyseq, *old, *new, *pl;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
-      old = get_command_bindings (lang, name, command);
-      new = mplist ();
-      for (pl = old;
-          pl && mplist_key (pl) == Mplist;
-          pl = mplist_next (pl))
-       if (! keyseq_equal (mplist_value (pl), keyseq))
-         mplist_add (new, Mplist, mplist_value (pl));
-      minput_config_command (lang, name, command, new);
-      m17n_object_unref (new);
-      gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-    }
-}
-
-static MPlist *entry_keyseq;
-
-static void
 update_entry (GtkEntry *entry)
 {
   if (mplist_key (entry_keyseq) == Mnil)
@@ -145,23 +87,34 @@ update_entry (GtkEntry *entry)
     }
 }
 
-enum KeyMaskBit {
-  META_MASK_BIT = 1,
-  ALT_MASK_BIT = META_MASK_BIT << 1,
-  SUPER_MASK_BIT = ALT_MASK_BIT << 1,
-  HYPER_MASK_BIT = SUPER_MASK_BIT << 1
-};
+static void
+update_binding_store (GtkWidget *view)
+{
+  GtkListStore *store;
+  GtkTreeIter iter;
+  MPlist *pl;
 
-static unsigned modifier_state = 0;
+  store =  GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
+  gtk_list_store_clear (store);
+
+  for (pl = CURRENT_BINDINGS;
+       pl && mplist_key (pl) == Mplist;
+       pl = mplist_next (pl))
+    {
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter, 0, mplist_value (pl), -1);
+    }
+}
 
 gboolean
-key_pressed (GtkEntry *entry, GdkEventKey *event, gpointer data)
+key_pressed_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
 {
   guint c;
   MText *mt;
   char buf[32];
   char *name;
   int nbytes, i;
+  struct BindingWidgets *bw = data;
 
   c = gdk_keyval_to_unicode (event->keyval);
   if (c == 0)
@@ -211,11 +164,13 @@ key_pressed (GtkEntry *entry, GdkEventKey *event, gpointer data)
   buf[i + nbytes] = 0;
   mplist_add (entry_keyseq, Msymbol, msymbol (buf));
   update_entry (entry);
+  gtk_widget_set_sensitive (bw->clear, TRUE);
+  gtk_widget_set_sensitive (bw->add, TRUE);
   return TRUE;
 }
 
 gboolean
-key_released (GtkEntry *entry, GdkEventKey *event, gpointer data)
+key_released_cb (GtkEntry *entry, GdkEventKey *event, gpointer data)
 {
   guint c;
 
@@ -238,25 +193,31 @@ key_released (GtkEntry *entry, GdkEventKey *event, gpointer data)
 }
 
 static void
-clear_cb (GtkButton *button, GtkWidget *entry)
+clear_cb (GtkButton *button, gpointer data)
 {
+  struct BindingWidgets *bw = data;
+
   mplist_set (entry_keyseq, Mnil, NULL);
-  gtk_widget_grab_focus (entry);
-  update_entry (GTK_ENTRY (entry));
+  gtk_widget_grab_focus (bw->entry);
+  update_entry (GTK_ENTRY (bw->entry));
+  gtk_widget_set_sensitive (bw->clear, FALSE);
+  gtk_widget_set_sensitive (bw->add, FALSE);
 }
 
 static void
-add_cb (GtkButton *button, GtkListStore *store)
+add_cb (GtkButton *button, gpointer data)
 {
-  MPlist *old, *new, *pl, *last;
+  MPlist *new, *pl, *last;
+  GtkListStore *store;
   GtkTreeIter iter;
-  GtkWidget *view;
+  struct BindingWidgets *bw = data;
 
   if (mplist_length (entry_keyseq) == 0)
     return;
-  old = get_command_bindings (current_lang, current_name, current_command);
   new = mplist ();
-  for (pl = old; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
+  for (pl = CURRENT_BINDINGS;
+       pl && mplist_key (pl) == Mplist;
+       pl = mplist_next (pl))
     {
       if (! keyseq_equal (mplist_value (pl), entry_keyseq))
        mplist_add (new, Mplist, mplist_value (pl));
@@ -268,144 +229,342 @@ add_cb (GtkButton *button, GtkListStore *store)
        }
     }
   mplist_add (new, Mplist, entry_keyseq);
-  minput_config_command (current_lang, current_name, current_command, new);
+  CONFIG_COMMAND (new);
   m17n_object_unref (new);
 
   /* We cannot use ENTRY_KEYSEQ for gtk_list_store_set ().  We must
      use a pointer to the internally copied one. */
-  new = get_command_bindings (current_lang, current_name, current_command);
-  for (pl = new; pl && mplist_key (pl) == Mplist;
-       last = pl, pl = mplist_next (pl))
+  new = CURRENT_BINDINGS;
+  for (pl = new;
+       pl && mplist_key (pl) == Mplist;
+       last = pl, pl = mplist_next (pl));
+  store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (bw->view)));
   gtk_list_store_append (store, &iter);
   gtk_list_store_set (store, &iter, 0, mplist_value (last), -1);
-  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  update_binding_store (bw->view);
+  clear_cb (NULL, bw);
+  gtk_widget_set_sensitive (bw->clear, FALSE);
+  gtk_widget_set_sensitive (bw->add, FALSE);
+}
+
+static GtkWidget *
+create_adding_section (struct BindingWidgets *bw)
+{
+  GtkWidget *label, *hbox, *vbox;
+
+  label = gtk_label_new (_("New key binding:"));
+
+  entry_keyseq = mplist ();
+  bw->entry = gtk_entry_new ();
+  g_signal_connect (G_OBJECT (bw->entry), "key-press-event",
+                   G_CALLBACK (key_pressed_cb), bw);
+  g_signal_connect (G_OBJECT (bw->entry), "key-release-event",
+                   G_CALLBACK (key_released_cb), bw);
+
+  bw->clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
+  gtk_widget_set_sensitive (bw->clear, FALSE);
+  g_signal_connect (G_OBJECT (bw->clear), "clicked",
+                   G_CALLBACK (clear_cb), bw);
+
+  bw->add = gtk_button_new_from_stock (GTK_STOCK_ADD);
+  gtk_widget_set_sensitive (bw->add, FALSE);
+  g_signal_connect (G_OBJECT (bw->add), "clicked",
+                   G_CALLBACK (add_cb), bw);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (vbox), hbox);
+
+  gtk_container_add (GTK_CONTAINER (vbox), bw->entry);
+
+  hbox = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbox), 6);
+  gtk_container_add (GTK_CONTAINER (hbox), bw->clear);
+  gtk_container_add (GTK_CONTAINER (hbox), bw->add);
+  gtk_container_add (GTK_CONTAINER (vbox), hbox);
+
+  return vbox;
 }
 
 static void
-command_cb (GtkButton *button, GtkWidget *frame)
+selection_cb (GtkTreeSelection *selection, gpointer data)
 {
-  GtkWidget *dialog, *view, *scrolled;
-  GtkWidget *delete, *entry, *add, *clear;
-  GtkListStore *store;
-  GtkTreeIter iter;
-  GtkTreeViewColumn *column;
-  GtkCellRenderer *renderer;
-  MPlist *bindings, *pl, *cmd;
-  gint response;
+  struct BindingWidgets *bw = data;
 
-  current_lang = g_object_get_data (G_OBJECT (button), "mim_lang");
-  current_name = g_object_get_data (G_OBJECT (button), "mim_name");
-  current_command = g_object_get_data (G_OBJECT (button), "mim_command");
-  bindings = get_command_bindings (current_lang, current_name, current_command);
+  gtk_widget_set_sensitive
+    (bw->delete,
+     gtk_tree_selection_count_selected_rows (selection) ? TRUE : FALSE);
+}
 
-  dialog = (gtk_dialog_new_with_buttons
-           (msymbol_name (current_command),
-            GTK_WINDOW (gtk_widget_get_toplevel (frame)),
-            GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
-            GTK_STOCK_OK, GTK_RESPONSE_OK,
-            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-            NULL));
+static void
+keyseq_render_function (GtkTreeViewColumn *column,
+                       GtkCellRenderer *renderer,
+                       GtkTreeModel *model,
+                       GtkTreeIter *iter,
+                       gpointer data)
+{
+  MPlist *keyseq, *pl;
+  gint n;
+  gchar buf[1024];
 
-  store = gtk_list_store_new (1, G_TYPE_POINTER);
-  for (pl = bindings; pl && mplist_key (pl) == Mplist; pl = mplist_next (pl))
+  gtk_tree_model_get (model, iter, 0, &keyseq, -1);
+  for (pl = keyseq, n = 0;
+       pl && mplist_key (pl) == Msymbol;
+       pl = mplist_next (pl))
+    n += strlen (msymbol_name ((MSymbol) mplist_value (pl))) + 1;
+  if (n < sizeof (buf))
     {
-      gtk_list_store_append (store, &iter);
-      gtk_list_store_set (store, &iter, 0, mplist_value (pl), -1);
+      buf[0] = '\0';
+      for (pl = keyseq;
+          pl && mplist_key (pl) == Msymbol;
+          pl = mplist_next (pl))
+       {
+         strcat (buf, msymbol_name ((MSymbol) mplist_value (pl)));
+         strcat (buf, " ");
+       }
+      g_object_set (renderer, "foreground-set", FALSE, NULL);
     }
-  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  else
+    {
+      g_snprintf (buf, sizeof (buf), _("Too long to display"));
+      g_object_set (renderer, "foreground", "Red", "foreground-set", TRUE,
+                   NULL);
+    }
+  g_object_set (renderer, "text", buf, NULL);
+}
+
+static void *
+default_cb (GtkButton *button, gpointer data)
+{
+  MPlist *empty = mplist ();
+  struct BindingWidgets *bw = data;
+
+  CONFIG_COMMAND (empty);
+  m17n_object_unref (empty);
+  update_binding_store (bw->view);
+}
+
+static void *
+revert_cb (GtkButton *button, gpointer data)
+{
+  struct BindingWidgets *bw = data;
+
+  CONFIG_COMMAND (NULL);
+  update_binding_store (bw->view);
+}
+
+static void
+delete_cb (GtkButton *button, gpointer data)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  MPlist *keyseq, *new, *pl;
+  struct BindingWidgets *bw = data;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (bw->view));
+  if (! gtk_tree_selection_get_selected (selection, &model, &iter))
+    return;
+  gtk_tree_model_get (model, &iter, 0, &keyseq, -1);
+  new = mplist ();
+  for (pl = CURRENT_BINDINGS;
+       pl && mplist_key (pl) == Mplist;
+       pl = mplist_next (pl))
+    if (! keyseq_equal (mplist_value (pl), keyseq))
+      mplist_add (new, Mplist, mplist_value (pl));
+  CONFIG_COMMAND (new);
+  m17n_object_unref (new);
+  gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+  update_binding_store (bw->view);
+  gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+}
+
+static GtkWidget *
+create_deleting_section (struct BindingWidgets *bw)
+{
+  GtkListStore *store;
+  GtkWidget *scrolled, *default_, *revert, *delete, *hbox, *vbox;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  GtkTreeIter iter;
+  GtkTreeSelection *selection;
+  MPlist *pl;
+
+  store = gtk_list_store_new (1, G_TYPE_POINTER);
+  bw->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
   g_object_unref (G_OBJECT (store));
+  update_binding_store (bw->view);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(bw->view));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+  g_signal_connect (G_OBJECT (selection), "changed",
+                   G_CALLBACK (selection_cb), bw);
+
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                        bw->view);
+
   column = gtk_tree_view_column_new ();
-  gtk_tree_view_column_set_title (column, "Current bindings");
-  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+  gtk_tree_view_column_set_title (column, _("Current Key Bindings"));
+  gtk_tree_view_append_column (GTK_TREE_VIEW (bw->view), column);
+
   renderer = gtk_cell_renderer_text_new ();
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func
     (column, renderer, keyseq_render_function, NULL, NULL);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), view);
 
-  delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
-  g_signal_connect (G_OBJECT (delete), "clicked",
-                   G_CALLBACK (delete_cb), view);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), delete);
+  default_ = gtk_button_new_from_stock (_("_Default"));
+  g_signal_connect (G_OBJECT (default_), "clicked",
+                   G_CALLBACK (default_cb), bw);
 
-  entry_keyseq = mplist ();
+  revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
+  g_signal_connect (G_OBJECT (revert), "clicked",
+                   G_CALLBACK (revert_cb), bw);
 
-  entry = gtk_entry_new ();
-  g_signal_connect (G_OBJECT (entry), "key-press-event",
-                   G_CALLBACK (key_pressed), NULL);
-  g_signal_connect (G_OBJECT (entry), "key-release-event",
-                   G_CALLBACK (key_released), NULL);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), entry);
+  bw->delete = gtk_button_new_from_stock (GTK_STOCK_DELETE);
+  gtk_widget_set_sensitive (bw->delete, FALSE);
+  g_signal_connect (G_OBJECT (bw->delete), "clicked",
+                   G_CALLBACK (delete_cb), bw);
 
-  clear = gtk_button_new_from_stock (GTK_STOCK_CLEAR);
-  g_signal_connect (G_OBJECT (clear), "clicked",
-                   G_CALLBACK (clear_cb), entry);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), clear);
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
 
-  add = gtk_button_new_from_stock (GTK_STOCK_ADD);
-  g_signal_connect (G_OBJECT (add), "clicked",
-                   G_CALLBACK (add_cb), store);
-  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), add);
+  gtk_container_add (GTK_CONTAINER (vbox), scrolled);
+
+  hbox = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbox), 6);
+  gtk_container_add (GTK_CONTAINER (hbox), default_);
+  gtk_container_add (GTK_CONTAINER (hbox), revert);
+  gtk_container_add (GTK_CONTAINER (hbox), bw->delete);
+  gtk_container_add (GTK_CONTAINER (vbox), hbox);
+
+  return vbox;
+}
+
+static void
+set_status (GtkListStore *store, GtkTreeIter *iter)
+{
+  MSymbol status;
+  gchar *status_str;
+
+  status = CURRENT_STATUS;
+  if (status == Mnil || status == Minherited)
+    status_str = _("default");
+  else if (status == Mcustomized)
+    status_str = _("customized");
+  else
+    status_str = _("modified");
+  gtk_list_store_set (store, iter, 1, status_str, -1);
+}
+
+static void
+activated_cb (GtkTreeView *parent, GtkTreePath *path,
+             GtkTreeViewColumn *col, gpointer data)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkWidget *dialog;
+  struct BindingWidgets bw;
+  gchar *command;
+
+  model = gtk_tree_view_get_model (parent);
+  if (! gtk_tree_model_get_iter (model, &iter, path))
+    return;
+  gtk_tree_model_get (model, &iter, 0, &command, -1);
+  current_command = msymbol (command);
+
+  dialog = (gtk_dialog_new_with_buttons
+           (command,
+            GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
+            GTK_DIALOG_DESTROY_WITH_PARENT,
+            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+            NULL));
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
+                    create_adding_section (&bw));
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
+                    create_deleting_section (&bw));
 
   gtk_widget_show_all (dialog);
-  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_tree_model_get_iter (model, &iter, path);
+  set_status (GTK_LIST_STORE (model), &iter);
   gtk_widget_destroy (dialog);
-
   m17n_object_unref (entry_keyseq);
 }
 
-void
-create_command_entries (GtkWidget *frame, GtkTooltips *tip,
-                       MSymbol lang, MSymbol name)
+GtkWidget *
+create_command_entries (GtkTooltips *tip, MSymbol lang, MSymbol name)
 {
-  GtkWidget *vbox;
+  GtkListStore *store;
+  GtkWidget *view;
+  GtkCellRenderer *renderer;
   MPlist *plist;
 
-  plist = minput_get_command (lang, name, Mnil);
-  if (! plist)
-    {
-      GtkWidget *message;
-
-      message = gtk_label_new ("No commands for this method");
-      gtk_container_add (GTK_CONTAINER (frame), message);
-      return;
-    }
+  current_lang = lang;
+  current_name = name;
 
+  plist = minput_get_command (lang, name, Mnil);
   /*
    * plist == ((command description status keyseq keyseq ...)
    *           (command description status keyseq keyseq ...)
    *           ...)
    */
-  vbox = gtk_vbox_new (FALSE, 0);
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
+  if (! plist)
+    return gtk_label_new (_("No commands for this method."));
 
+  store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
   for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
     {
-      GtkWidget *button;
+      GtkTreeIter iter;
       MPlist *pl;
-      MSymbol command;
+      MSymbol command, status;
       gchar *desc;
+      gchar *status_str;
 
       pl = mplist_value (plist);
       /* pl == (command description status keyseq keyseq ...) */
-      command = mplist_value (pl);
-      button = gtk_button_new_with_label (msymbol_name (command));
-      gtk_container_add (GTK_CONTAINER (vbox), button);
+      current_command = command = mplist_value (pl);
 
-      pl = mplist_next (pl);
+      pl = mplist_next (pl); 
       /* pl == (description status keyseq keyseq ...) */
       if (mplist_key (pl) == Mtext)
        /* Fixme : Assuming the return value is in UTF-8 */
        desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
       else
        desc = NULL;
-      gtk_tooltips_set_tip (tip, button, desc, NULL);
 
-      g_object_set_data (G_OBJECT (button), "mim_lang", lang);
-      g_object_set_data (G_OBJECT (button), "mim_name", name);
-      g_object_set_data (G_OBJECT (button), "mim_command", command);
-      g_signal_connect (G_OBJECT (button), "clicked",
-                       G_CALLBACK (command_cb), frame);
+      pl = mplist_next (pl);
+      /* pl == (status keyseq keyseq ...) */
+      status = mplist_value (pl);
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                         0, msymbol_name (command),
+                         -1);
+      set_status (store, &iter);
     }
+  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  g_object_unref (G_OBJECT (store));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+                                              -1,      
+                                              _("Name"),
+                                              renderer,
+                                              "text", 0,
+                                              NULL);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+                                              -1,      
+                                              _("Status"),
+                                              renderer,
+                                              "text", 1,
+                                              NULL);
+  g_signal_connect (G_OBJECT (view), "row-activated",
+                   G_CALLBACK (activated_cb), NULL);
+  return view;
 }
-
index 697a763..fff6c90 100644 (file)
@@ -78,12 +78,14 @@ get_mim_status (MSymbol lang, MSymbol name)
       MPlist *p = mplist_value (plist);
       MSymbol status_symbol;
 
-      status = MIM_STATUS_DEFAULT;
+      if (status == MIM_STATUS_NO)
+       status = MIM_STATUS_DEFAULT;
       p = mplist_next (mplist_next (p));
       status_symbol = mplist_value (p);
-      if (status_symbol != Mnil && status_symbol != Minherited)
-       return (status_symbol == Mcustomized
-               ? MIM_STATUS_CUSTOMIZED : MIM_STATUS_MODIFIED);
+      if (status_symbol == Mconfigured)
+       return MIM_STATUS_MODIFIED;
+      if (status_symbol == Mcustomized)
+       status = MIM_STATUS_CUSTOMIZED;
     }
   for (plist = minput_get_command (lang, name, Mnil);
        plist && mplist_key (plist) != Mnil; plist = mplist_next (plist))
@@ -91,12 +93,14 @@ get_mim_status (MSymbol lang, MSymbol name)
       MPlist *p = mplist_value (plist);
       MSymbol status_symbol;
 
-      status = MIM_STATUS_DEFAULT;
+      if (status == MIM_STATUS_NO)
+       status = MIM_STATUS_DEFAULT;
       p = mplist_next (mplist_next (p));
       status_symbol = mplist_value (p);
-      if (status_symbol != Mnil && status_symbol != Minherited)
-       return (status_symbol == Mcustomized
-               ? MIM_STATUS_CUSTOMIZED : MIM_STATUS_MODIFIED);
+      if (status_symbol == Mconfigured)
+       return MIM_STATUS_MODIFIED;
+      if (status_symbol == Mcustomized)
+       status = MIM_STATUS_CUSTOMIZED;
     }
   return status;
 }
@@ -158,41 +162,58 @@ tree_expanded_cb (GtkTreeView *tree, GtkTreeIter *parent,
     }
 }
 
+extern GtkWidget *create_variable_entries (GtkTooltips *tip, MSymbol lang,
+                                              MSymbol name);
+extern GtkWidget *create_command_entries (GtkTooltips *tip, MSymbol lang,
+                                             MSymbol name);
+
 static void
 edit_im (GtkTreeView *tree, MSymbol lang, MSymbol name)
 {
-  GtkWidget *dialog, *frame, *table;
+  GtkWidget *dialog, *notebook, *scrolled, *vbox, *label;
   GtkTooltips *tip = gtk_tooltips_new ();
   gint response;
   MPlist *plist;
 
   dialog = (gtk_dialog_new_with_buttons
-           (msymbol_name (name),
+           (name == Mnil ? "global" : msymbol_name (name),
             GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree))),
             GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
-            _("Default"), 0,
-            GTK_STOCK_REVERT_TO_SAVED, GTK_RESPONSE_NO,
-            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
             NULL));
+  gtk_widget_set_size_request (dialog, 500, 300);
+
+  notebook = gtk_notebook_new ();
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), notebook);
 
-  frame = gtk_frame_new (_("Variables"));
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
+  /* Variables' page */
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  label = gtk_label_new_with_mnemonic ("_Variables");
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                        vbox);
+  gtk_box_pack_start (GTK_BOX (vbox),
+                     create_variable_entries (tip, lang, name),
                      FALSE, FALSE, 0);
-  create_variable_entries (frame, tip, lang, name);
 
-  frame = gtk_frame_new (_("Commands"));
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), frame,
+  /* Commands' pages */
+  scrolled = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  label = gtk_label_new_with_mnemonic ("Co_mmands");
+  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled, label);
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                        vbox);
+  gtk_box_pack_start (GTK_BOX (vbox),
+                     create_command_entries (tip, lang, name),
                      FALSE, FALSE, 0);
-  create_command_entries (frame, tip, lang, name);
 
   gtk_widget_show_all (dialog);
-  response = gtk_dialog_run (GTK_DIALOG (dialog));
-  if (response == 0)
-    printf ("Default\n");
-  else if (response == GTK_RESPONSE_NO)
-    printf ("GTK_RESPONSE_NO\n");
-  else if (response == GTK_RESPONSE_CANCEL)
-    printf ("GTK_RESPONSE_CANCEL\n");
+  gtk_dialog_run (dialog);
   gtk_widget_destroy (dialog);
 }
 
@@ -495,7 +516,7 @@ mim_config_new (GCallback func, gpointer data)
 
   renderer = gtk_cell_renderer_text_new ();
   column = (gtk_tree_view_column_new_with_attributes
-           (_("status"), renderer, "text", COL_STATUS_STR, NULL));
+           (_("Status"), renderer, "text", COL_STATUS_STR, NULL));
   gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
   g_signal_connect (G_OBJECT (tree), "row-expanded",
index b8475da..cb6fe9d 100644 (file)
@@ -1,35 +1,74 @@
-#include <gtk/gtk.h>
-#include <m17n.h>
 #include <stdio.h>
 #include <string.h>
+#include <libintl.h>
+#include <gtk/gtk.h>
+#include <m17n.h>
+#include <config.h>
+
+#define _(String) dgettext (PACKAGE, String)
+
+#define CURRENT_VALUE          \
+  (mplist_next                 \
+   (mplist_next                        \
+    (mplist_next               \
+     (mplist_value             \
+      (minput_get_variable     \
+       (current_lang, current_name, current_variable))))))
+
+#define CURRENT_STATUS         \
+  (mplist_next                 \
+   (mplist_next                        \
+    (mplist_value              \
+     (minput_get_variable      \
+      (current_lang, current_name, current_variable)))))
+
+#define CONFIG_VARIABLE(plist)                                         \
+  minput_config_variable (current_lang, current_name, current_variable,        \
+                         (plist))
+
+enum WidgetType
+  {
+    ENTRY_WIDGET,
+    COMBO_BOX_WIDGET,
+    SPIN_BUTTON_WIDGET
+  };
+
+struct ControllerInfo
+{
+  /* type of current variable: Minteger, Msymbol, or Mtext */
+  MSymbol vtype;
+
+  /* widget showing and controlling current variable */
+  GtkWidget *widget;
+
+  /* type of widget */
+  enum WidgetType wtype;
+};
+
+static MSymbol current_lang, current_name, current_variable;
 
 static void
-entry_cb (GtkWidget *entry, gpointer data)
+entry_cb (GtkEntry *entry, gpointer data)
 {
-  const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
-  MSymbol lang, name, variable, key;
+  const gchar *text = gtk_entry_get_text (entry);
   MPlist *plist = mplist ();
+  struct ControllerInfo *ci = data;
 
-  lang = g_object_get_data (G_OBJECT (entry), "mim_lang");
-  name = g_object_get_data (G_OBJECT (entry), "mim_name");
-  variable = g_object_get_data (G_OBJECT (entry), "mim_variable");
-  key = g_object_get_data (G_OBJECT (entry), "mim_key");
-
-  if (key == Msymbol)
+  if (ci->vtype == Msymbol)
     {
       mplist_add (plist, Msymbol, msymbol (text));
-      minput_config_variable (lang, name, variable, plist);
+      CONFIG_VARIABLE (plist);
     }
-  else if (key == Mtext)
+  else if (ci->vtype == Mtext)
     {
       MText *mt;
 
       mt = mtext_from_data (text, strlen (text), MTEXT_FORMAT_UTF_8);
       mplist_add (plist, Mtext, mt);
-      minput_config_variable (lang, name, variable, plist);
+      CONFIG_VARIABLE (plist);
       m17n_object_unref (mt);
     }
-  else if (key == Minteger)
+  else if (ci->vtype == Minteger)
     {
       int i;
       gchar buf[32];
@@ -37,13 +76,25 @@ entry_cb (GtkWidget *entry, gpointer data)
       if (sscanf (text, "%d", &i) == 1)
        {
          mplist_add (plist, Minteger, (void *) i);
-           minput_config_variable (lang, name, variable, plist);
+         CONFIG_VARIABLE (plist);
        }
       else
        {
-         printf ("Invalid value\n");
+         GtkWidget *msg;
+
+         msg = gtk_message_dialog_new (GTK_WINDOW
+                                       (gtk_widget_get_toplevel (ci->widget)),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_CLOSE,
+                                       _("The value must be an integer."));
+         gtk_dialog_run (GTK_DIALOG (msg));
+         gtk_widget_destroy (msg);
+         /* revert current value */
+         mplist_add (plist, Minteger, mplist_value (CURRENT_VALUE));
        }
-      sprintf (buf, "%d", (int) mplist_value (plist));
+      /* redraw the value to get rid of non-digits */
+      g_snprintf (buf, sizeof (buf), "%d", (gint) mplist_value (plist));
       gtk_entry_set_text (GTK_ENTRY (entry), buf);
       gtk_editable_set_position (GTK_EDITABLE (entry), -1);
     }
@@ -51,251 +102,449 @@ entry_cb (GtkWidget *entry, gpointer data)
 }
 
 static void
-combo_cb (GtkWidget *combo, gpointer data)
+combo_cb (GtkComboBox *combo, gpointer data)
 {
-  gchar *text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combo));
-  MSymbol lang, name, variable, key;
+  gchar *text = gtk_combo_box_get_active_text (combo);
   MPlist *plist = mplist ();
+  struct ControllerInfo *ci = data;
 
-  lang = g_object_get_data (G_OBJECT (combo), "mim_lang");
-  name = g_object_get_data (G_OBJECT (combo), "mim_name");
-  variable = g_object_get_data (G_OBJECT (combo), "mim_variable");
-  key = g_object_get_data (G_OBJECT (combo), "mim_key");
 
-  if (key == Msymbol)
+  if (ci->vtype == Msymbol)
     {
       mplist_add (plist, Msymbol, msymbol (text));
-      minput_config_variable (lang, name, variable, plist);
+      CONFIG_VARIABLE (plist);
     }
-  else if (key == Mtext)
+  else if (ci->vtype == Mtext)
     {
       MText *mt;
 
       mt = mtext_from_data (text, strlen (text), MTEXT_FORMAT_UTF_8);
       mplist_add (plist, Mtext, mt);
-      minput_config_variable (lang, name, variable, plist);
+      CONFIG_VARIABLE (plist);
       m17n_object_unref (mt);
     }
-  else if (key == Minteger)
+  else if (ci->vtype == Minteger)
     {
       int i;
-      gchar buf[32];
 
-      if (sscanf (text, "%d", &i) == 1)
-       {
-         mplist_add (plist, Minteger, (void *) i);
-         minput_config_variable (lang, name, variable, plist);
-       }
-      else
-       {
-         printf ("Invalid value\n");
-       }
+      sscanf (text, "%d", &i);
+      mplist_add (plist, Minteger, (void *) i);
+      CONFIG_VARIABLE (plist);
     }
   m17n_object_unref (plist);
 }
 
 static void
-spin_cb (GtkWidget *spin, gpointer data)
+spin_cb (GtkSpinButton *spin, gpointer data)
 {
-  MSymbol lang, name, variable;
   MPlist *plist = mplist ();
+  struct ControllerInfo *ci = data;
 
-  lang = g_object_get_data (G_OBJECT (spin), "mim_lang");
-  name = g_object_get_data (G_OBJECT (spin), "mim_name");
-  variable = g_object_get_data (G_OBJECT (spin), "mim_variable");
-
-  mplist_add
-    (plist, Minteger,
-     (void *) gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)));
-  minput_config_variable (lang, name, variable, plist);
+  mplist_add (plist, Minteger,
+             (void *) gtk_spin_button_get_value_as_int (spin));
+  CONFIG_VARIABLE (plist);
   m17n_object_unref (plist);
 }
 
-void
-create_variable_entries (GtkWidget *frame, GtkTooltips *tip,
-                        MSymbol lang, MSymbol name)
+enum
+  {
+    VCOL_VARIABLE,
+    VCOL_VALUE,
+    VCOL_STATUS,
+    NUM_VCOLS
+  };
+
+static void
+set_value_status (GtkListStore *store, GtkTreeIter *iter)
 {
-  GtkWidget *table;
   MPlist *plist;
-  gint row;
-
-  plist = minput_get_variable (lang, name, Mnil);
-  if (! plist)
-    {
-      GtkWidget *message;
+  MSymbol status;
+  gchar *value_str, *status_str, buf[32];
 
-      message = gtk_label_new ("No variables for this method");
-      gtk_container_add (GTK_CONTAINER (frame), message);
-      return;
-    }
+  plist = CURRENT_STATUS;
+  /* plist == (status value [valid-value ...]) */
+  status = mplist_value (plist);
+  if (status == Mnil || status == Minherited)
+    status_str = _("default");
+  else if (status == Mcustomized)
+    status_str = _("customized");
+  else
+    status_str = _("modified");
 
-  /*
-   * plist == ((variable description status value [valid-value ...])
-   *           (variable description status value [valid-value ...])
-   *           ...)
-   */
-  table = gtk_table_new (2, mplist_length (plist), FALSE);
-  gtk_container_add (GTK_CONTAINER (frame), table);
-
-  for (row = 0; plist && mplist_key (plist) == Mplist;
-       row++, plist = mplist_next (plist))
+  plist = mplist_next (plist);
+  /* plist == (value [valid-value ...]) */
+  if (mplist_key (plist) == Msymbol)
+    value_str = msymbol_name ((MSymbol) mplist_value (plist));
+  else if (mplist_key (plist) == Mtext)
+    /* Fixme : Assuming the return value is in UTF-8 */
+    value_str = mtext_data ((MText *) mplist_value (plist),
+                           NULL, NULL, NULL, NULL);
+  else
     {
-      GtkWidget *label, *widget;
-      MPlist *pl, *data;
-      MSymbol variable, key;
-      void *value;
-      gchar *desc;
+      g_snprintf (buf, sizeof (buf), "%d", (gint) mplist_value (plist));
+      value_str = buf;
+    }
 
-      pl = mplist_value (plist);
-      variable = mplist_value (pl);
-      label = gtk_label_new (msymbol_name (variable));
-      gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, row, row + 1);
+  gtk_list_store_set (store, iter,
+                     VCOL_VALUE, value_str,
+                     VCOL_STATUS, status_str,
+                     -1);
+}
 
-      pl = mplist_next (pl);
-      if (mplist_key (pl) == Mtext)
-       /* Fixme : Assuming the return value is in UTF-8 */
-       desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
-      else
-       desc = NULL;
+static GtkWidget *
+create_widget (struct ControllerInfo *ci)
+{
+  MPlist *plist;
+  void *value;
 
-      pl = mplist_next (mplist_next (pl)); /* ignore status */
-      key = mplist_key (pl);
-      value = mplist_value (pl);
-      pl = mplist_next (pl);
+  plist = CURRENT_VALUE;
+  /* plist == (value [valid-value ...]) */
+  ci->vtype = mplist_key (plist);
+  value = mplist_value (plist);
+  plist = mplist_next (plist);
 
-      if (key == Msymbol)
+  if (ci->vtype == Msymbol)
+    {
+      if (plist && mplist_key (plist) == Msymbol)
        {
-         if (mplist_key (pl) == Msymbol)
-           {
-             int i, nth = -1;
-
-             widget = gtk_combo_box_new_text ();
-             for (i = 0; pl && mplist_key (pl) == Msymbol;
-                  pl = mplist_next (pl), i++)
-               {
-                 if (mplist_value (pl) == value)
-                   nth = i;
-                 gtk_combo_box_append_text (GTK_COMBO_BOX (widget),
-                                            msymbol_name (mplist_value (pl)));
-               }
-             if (nth != -1)
-               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
-             g_signal_connect (G_OBJECT (widget), "changed",
-                               G_CALLBACK (combo_cb), NULL);
-           }
-         else
+         gint i, nth = -1;
+
+         ci->widget = gtk_combo_box_new_text ();
+         ci->wtype = COMBO_BOX_WIDGET;
+         for (i = 0; plist && mplist_key (plist) == Msymbol;
+              plist = mplist_next (plist), i++)
            {
-             widget = gtk_entry_new ();
-             gtk_entry_set_text (GTK_ENTRY (widget), msymbol_name (value));
-             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
-             g_signal_connect (G_OBJECT (widget), "activate",
-                               G_CALLBACK (entry_cb), NULL);
+             if (mplist_value (plist) == value)
+               nth = i;
+             gtk_combo_box_append_text
+               (GTK_COMBO_BOX (ci->widget),
+                msymbol_name ((MSymbol) mplist_value (plist)));
            }
+         if (nth != -1)
+           gtk_combo_box_set_active (GTK_COMBO_BOX (ci->widget), nth);
+         g_signal_connect (G_OBJECT (ci->widget), "changed",
+                           G_CALLBACK (combo_cb), ci);
        }
-      
-      else if (key == Mtext)
+      else
        {
-         if (mplist_key (pl) == Mtext)
-           {
-             int i, nth = -1;
-
-             widget = gtk_combo_box_new_text ();
-             for (i = 0; pl && mplist_key (pl) == Mtext;
-                  pl = mplist_next (pl), i++)
-               {
-                 if (! mtext_cmp (mplist_value (pl), value))
-                   nth = i;
-                 /* Fixme : Assuming the return value is in UTF-8 */
-                 gtk_combo_box_append_text
-                   (GTK_COMBO_BOX (widget),
-                    mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL));
-               }
-             if (nth != -1)
-               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
-             g_signal_connect (G_OBJECT (widget), "changed",
-                               G_CALLBACK (combo_cb), NULL);
-           }
-         else
+         ci->widget = gtk_entry_new ();
+         ci->wtype = ENTRY_WIDGET;
+         gtk_entry_set_text (GTK_ENTRY (ci->widget), msymbol_name (value));
+         gtk_editable_set_editable (GTK_EDITABLE (ci->widget), TRUE);
+         g_signal_connect (G_OBJECT (ci->widget), "activate",
+                           G_CALLBACK (entry_cb), ci);
+       }
+    }
+  else if (ci->vtype == Mtext)
+    {
+      if (plist && mplist_key (plist) == Mtext)
+       {
+         gint i, nth = -1;
+
+         ci->widget = gtk_combo_box_new_text ();
+         ci->wtype = COMBO_BOX_WIDGET;
+         for (i = 0; plist && mplist_key (plist) == Mtext;
+              plist = mplist_next (plist), i++)
            {
-             widget = gtk_entry_new ();
+             if (! mtext_cmp ((MText *) mplist_value (plist),
+                              (MText *) value))
+               nth = i;
              /* Fixme : Assuming the return value is in UTF-8 */
-             gtk_entry_set_text (GTK_ENTRY (widget),
-                                 mtext_data (value, NULL, NULL, NULL, NULL));
-             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
-             g_signal_connect (G_OBJECT (widget), "activate",
-                               G_CALLBACK (entry_cb), NULL);
+             gtk_combo_box_append_text
+               (GTK_COMBO_BOX (ci->widget),
+                mtext_data ((MText *) mplist_value (plist),
+                            NULL, NULL, NULL, NULL));
            }
+         if (nth != -1)
+           gtk_combo_box_set_active (GTK_COMBO_BOX (ci->widget), nth);
+         g_signal_connect (G_OBJECT (ci->widget), "changed",
+                           G_CALLBACK (combo_cb), ci);
        }
-
-      else if (key == Minteger)
+      else
        {
-         if (mplist_key (pl) == Minteger)
-           {
-             int i, nth = -1;
-
-             widget = gtk_combo_box_new_text ();
-             for (i = 0; pl && mplist_key (pl) == Minteger;
-                  pl = mplist_next (pl), i++)
-               {
-                 gchar buf[32];
-
-                 if (mplist_value (pl) == value)
-                   nth = i;
-                 snprintf (buf, 31, "%d", (int) mplist_value (pl));
-                 gtk_combo_box_append_text (GTK_COMBO_BOX (widget), buf);
-               }
-             if (nth != -1)
-               gtk_combo_box_set_active (GTK_COMBO_BOX (widget), nth);
-             g_signal_connect (G_OBJECT (widget), "changed",
-                               G_CALLBACK (combo_cb), NULL);
-           }
-         else if (mplist_key (pl) == Mplist)
-           {
-             GtkAdjustment *adj;
-             gdouble lower, upper;
-
-             pl = mplist_value (pl);
-             lower = (gdouble) (int) mplist_value (pl);
-             pl = mplist_next (pl);
-             upper = (gdouble) (int) mplist_value (pl);
-             adj = (GtkAdjustment *)
-               gtk_adjustment_new ((gdouble) (int) value, (gdouble) lower,
-                                   (gdouble) upper, 1.0, 10.0, 0);
-             widget = gtk_spin_button_new (adj, 0, 0);
-             gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
-             gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (widget),
-                                                GTK_UPDATE_IF_VALID);
-             g_signal_connect (G_OBJECT (widget), "value_changed",
-                               G_CALLBACK (spin_cb), NULL);
-           }
-         else
+         ci->widget = gtk_entry_new ();
+         ci->wtype = ENTRY_WIDGET;
+         /* Fixme : Assuming the return value is in UTF-8 */
+         gtk_entry_set_text (GTK_ENTRY (ci->widget),
+                             mtext_data (value, NULL, NULL, NULL, NULL));
+         gtk_editable_set_editable (GTK_EDITABLE (ci->widget), TRUE);
+         g_signal_connect (G_OBJECT (ci->widget), "activate",
+                           G_CALLBACK (entry_cb), ci);
+       }
+    }
+  else if (ci->vtype == Minteger)
+    {
+      if (plist && mplist_key (plist) == Minteger)
+       {
+         gint i, nth = -1;
+
+         ci->widget = gtk_combo_box_new_text ();
+         ci->wtype = COMBO_BOX_WIDGET;
+         for (i = 0; plist && mplist_key (plist) == Minteger;
+              plist = mplist_next (plist), i++)
            {
              gchar buf[32];
 
-             widget = gtk_entry_new ();
-             snprintf (buf, 31, "%d", (int) value);
-             gtk_entry_set_text (GTK_ENTRY (widget), buf);
-             gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
-             g_signal_connect (G_OBJECT (widget), "activate",
-                               G_CALLBACK (entry_cb), NULL);
+             if (mplist_value (plist) == value)
+               nth = i;
+             g_snprintf (buf, sizeof (buf), "%d",
+                         (gint) mplist_value (plist));
+             gtk_combo_box_append_text (GTK_COMBO_BOX (ci->widget), buf);
            }
+         if (nth != -1)
+           gtk_combo_box_set_active (GTK_COMBO_BOX (ci->widget), nth);
+         g_signal_connect (G_OBJECT (ci->widget), "changed",
+                           G_CALLBACK (combo_cb), ci);
        }
+      else if (plist && mplist_key (plist) == Mplist)
+       {
+         GtkObject *adj;
+         gdouble lower, upper;
 
+         plist = mplist_value (plist);
+         lower = (gdouble) (int) mplist_value (plist);
+         upper = (gdouble) (int) mplist_value (mplist_next (plist));
+         adj = gtk_adjustment_new ((gdouble) (int) value, lower, upper,
+                                   1.0, 10.0, 0);
+         ci->widget = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
+         ci->wtype = SPIN_BUTTON_WIDGET;
+         gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (ci->widget), TRUE);
+         gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (ci->widget),
+                                            GTK_UPDATE_IF_VALID);
+         g_signal_connect (G_OBJECT (ci->widget), "value_changed",
+                           G_CALLBACK (spin_cb), ci);
+       }
       else
        {
-         widget = gtk_entry_new ();
-         gtk_entry_set_text (GTK_ENTRY (widget), "???");
-         gtk_editable_set_editable (GTK_EDITABLE (widget), TRUE);
-         g_signal_connect (G_OBJECT (widget), "activate",
-                           G_CALLBACK (entry_cb), NULL);
+         gchar buf[32];
+
+         ci->widget = gtk_entry_new ();
+         ci->wtype = ENTRY_WIDGET;
+         g_snprintf (buf, sizeof (buf), "%d", (gint) value);
+         gtk_entry_set_text (GTK_ENTRY (ci->widget), buf);
+         gtk_editable_set_editable (GTK_EDITABLE (ci->widget), TRUE);
+         g_signal_connect (G_OBJECT (ci->widget), "activate",
+                           G_CALLBACK (entry_cb), ci);
        }
+    }
+  else
+    {
+      ci->widget = gtk_entry_new ();
+      ci->wtype = ENTRY_WIDGET;
+      gtk_entry_set_text (GTK_ENTRY (ci->widget), "???");
+      gtk_editable_set_editable (GTK_EDITABLE (ci->widget), TRUE);
+      g_signal_connect (G_OBJECT (ci->widget), "activate",
+                       G_CALLBACK (entry_cb), ci);
+    }
+  return ci->widget;
+}
 
-      gtk_tooltips_set_tip (tip, widget, desc, NULL);
-      g_object_set_data (G_OBJECT (widget), "mim_lang", lang);
-      g_object_set_data (G_OBJECT (widget), "mim_name", name);
-      g_object_set_data (G_OBJECT (widget), "mim_variable", variable);
-      g_object_set_data (G_OBJECT (widget), "mim_key", key);
-      gtk_table_attach_defaults        (GTK_TABLE (table), widget,
-                                1, 2, row, row + 1);
+static void
+update_controller (struct ControllerInfo *ci)
+{
+  MPlist *plist;
+  MSymbol key;
+  void *value;
+
+  plist = CURRENT_VALUE;
+  /* plist == (value [valid-value ...]) */
+  key = mplist_key (plist);
+  value = mplist_value (plist);
+
+  if (ci->wtype == ENTRY_WIDGET)
+    {
+      if (key == Msymbol)
+       gtk_entry_set_text (GTK_ENTRY (ci->widget),
+                           msymbol_name ((MSymbol) value));
+      else if (key == Mtext)           
+       /* Fixme : Assuming the return value is in UTF-8 */
+       gtk_entry_set_text (GTK_ENTRY (ci->widget),
+                           mtext_data ((MText *) value,
+                                       NULL, NULL, NULL, NULL));
+      else
+       {
+         gchar buf[32];
+         g_snprintf (buf, sizeof (buf), "%d", (gint) value);
+         gtk_entry_set_text (GTK_ENTRY (ci->widget), buf);
+       }
+    }
+  else if (ci->wtype == COMBO_BOX_WIDGET)
+    {
+      gint i;
+
+      for (i = 0, plist = mplist_next (plist);
+          plist && mplist_key (plist) == key;
+          i++, plist = mplist_next (plist))
+       if (mplist_value (plist) == value)
+         break;
+      gtk_combo_box_set_active (GTK_COMBO_BOX (ci->widget), i);
+    }
+  else
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON (ci->widget),
+                              (gdouble) (int) value);
+}
+
+static void *
+default_cb (GtkButton *button, gpointer data)
+{
+  MPlist *empty = mplist ();
+
+  CONFIG_VARIABLE (empty);
+  m17n_object_unref (empty);
+  update_controller ((struct ControllerInfo *) data);
+}
+
+static void *
+revert_cb (GtkButton *button, gpointer data)
+{
+  CONFIG_VARIABLE (NULL);
+  update_controller ((struct ControllerInfo *) data);
+}
+
+static void *
+apply_cb (GtkButton *button, gpointer data)
+{
+  struct ControllerInfo *ci = data;
+
+  if (ci->wtype == ENTRY_WIDGET)
+    entry_cb (GTK_ENTRY (ci->widget), ci);
+}
+  
+static void
+activated_cb (GtkTreeView *parent, GtkTreePath *path,
+             GtkTreeViewColumn *col, gpointer data)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkWidget *dialog, *default_, *revert, *apply, *hbox, *vbox;
+  struct ControllerInfo ci;
+  gchar *variable;
+
+  model = gtk_tree_view_get_model (parent);
+  if (! gtk_tree_model_get_iter (model, &iter, path))
+    return;
+  gtk_tree_model_get (model, &iter, VCOL_VARIABLE, &variable, -1);
+  current_variable = msymbol (variable);
+
+  dialog = (gtk_dialog_new_with_buttons
+           (variable,
+            GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (parent))),
+            GTK_DIALOG_DESTROY_WITH_PARENT,
+            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+            NULL));
+
+  default_ = gtk_button_new_from_stock (_("_Default"));
+  g_signal_connect (G_OBJECT (default_), "clicked",
+                   G_CALLBACK (default_cb), &ci);
+
+  revert = gtk_button_new_from_stock (GTK_STOCK_REVERT_TO_SAVED);
+  g_signal_connect (G_OBJECT (revert), "clicked",
+                   G_CALLBACK (revert_cb), &ci);
+
+  apply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
+  g_signal_connect (G_OBJECT (apply), "clicked",
+                   G_CALLBACK (apply_cb), &ci);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
+
+  gtk_container_add (GTK_CONTAINER (vbox), create_widget (&ci));
+
+  hbox = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+  gtk_box_set_spacing (GTK_BOX (hbox), 6);
+  gtk_container_add (GTK_CONTAINER (hbox), default_);
+  gtk_container_add (GTK_CONTAINER (hbox), revert);
+  gtk_container_add (GTK_CONTAINER (hbox), apply);
+  gtk_container_add (GTK_CONTAINER (vbox), hbox);
+                     
+  gtk_widget_show_all (dialog);
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_tree_model_get_iter (model, &iter, path);
+  set_value_status (GTK_LIST_STORE (model), &iter);
+  gtk_widget_destroy (dialog);
+}
+
+GtkWidget *
+create_variable_entries (GtkTooltips *tip, MSymbol lang, MSymbol name)
+{
+  GtkListStore *store;
+  GtkWidget *view;
+  GtkCellRenderer *renderer;
+  MPlist *plist;
+
+  current_lang = lang;
+  current_name = name;
+
+  plist = minput_get_variable (lang, name, Mnil);
+  if (! plist)
+    return gtk_label_new (_("No variables for this method."));
+
+  /*
+   * plist == ((variable description status value [valid-value ...])
+   *           (variable description status value [valid-value ...])
+   *           ...)
+   */
+
+  store = gtk_list_store_new (NUM_VCOLS,
+                             G_TYPE_STRING,
+                             G_TYPE_STRING,
+                             G_TYPE_STRING);
+  for (; plist && mplist_key (plist) == Mplist; plist = mplist_next (plist))
+    {
+      GtkTreeIter iter;
+      MPlist *pl;
+      MSymbol variable, value, status;
+      gchar *desc;
+      gchar *status_str;
+
+      pl = mplist_value (plist);
+      /* pl == (variable description status value [valid-value ...]) */
+      current_variable = mplist_value (pl);
+
+      pl = mplist_next (pl); 
+      /* pl == (description status value [valid-value ...]) */
+      if (mplist_key (pl) == Mtext)
+       /* Fixme : Assuming the return value is in UTF-8 */
+       desc = mtext_data (mplist_value (pl), NULL, NULL, NULL, NULL);
+      else
+       desc = NULL;
+
+      pl = mplist_next (pl);
+      /* pl == (status value [valid-value ...]) */
+      status = mplist_value (pl);
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                         VCOL_VARIABLE, msymbol_name (current_variable),
+                         -1);
+      set_value_status (store, &iter);
     }
+  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+  g_object_unref (G_OBJECT (store));
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+                                              -1,      
+                                              _("Name"),
+                                              renderer,
+                                              "text",
+                                              VCOL_VARIABLE,
+                                              NULL);
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+                                              -1,      
+                                              _("Value"),
+                                              renderer,
+                                              "text",
+                                              VCOL_VALUE,
+                                              NULL);
+  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
+                                              -1,      
+                                              _("Status"),
+                                              renderer,
+                                              "text",
+                                              VCOL_STATUS,
+                                              NULL);
+  g_signal_connect (G_OBJECT (view), "row-activated",
+                   G_CALLBACK (activated_cb), NULL);
+  return view;
 }