Changed call to nl_langinfo with localecharset (from gnulib).
[pspp-builds.git] / src / ui / gui / var-sheet.c
index b38806bb1644dea49f20010011d65ac682b25baa..7936144951e15070fb0e1dd828ea20df53399cd0 100644 (file)
@@ -1,7 +1,6 @@
-/* 
+/*
    PSPPIRE --- A Graphical User Interface for PSPP
    Copyright (C) 2004, 2005, 2006  Free Software Foundation
-   Written by John Darrington
 
    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
 /* This module creates the Variable Sheet used for inputing the
    variables in the  dictonary */
 
+#include <config.h>
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
 #include <data/value-labels.h>
 
 #include <glade/glade.h>
 #include <stdlib.h>
 #include <string.h>
 
-#define min(A,B) ((A < B)?A:B)
+#include <data/value.h>
 
 #include <gtksheet/gtksheet.h>
 #include <gtksheet/gsheet-hetero-column.h>
 #include <gtksheet/gsheet-uniform-row.h>
 
+#include "localcharset.h"
 #include "psppire-var-store.h"
 #include "helper.h"
-#include "menu-actions.h"
 #include "psppire-dict.h"
-#include "psppire-variable.h"
 #include "var-type-dialog.h"
 #include "var-sheet.h"
 #include "customentry.h"
 #include "val-labs-dialog.h"
 #include "missing-val-dialog.h"
 
-#define _(A) A
-#define N_(A) A
 
 
 static const gint n_initial_rows = 40;
 
 
-extern GladeXML *xml;
 
 struct column_parameters
 {
-  gchar label[20];  
+  gchar label[20];
   gint width ;
 };
 
 static const struct column_parameters column_def[] = {
-  {N_("Name"),    80},
-  {N_("Type"),    100},
-  {N_("Width"),   57}, 
-  {N_("Decimals"),91}, 
-  {N_("Label"),   95}, 
-  {N_("Values"),  103},
-  {N_("Missing"), 95}, 
-  {N_("Columns"), 80}, 
-  {N_("Align"),   69}, 
-  {N_("Measure"), 99}, 
+  { N_("Name"),    80},
+  { N_("Type"),    100},
+  { N_("Width"),   57},
+  { N_("Decimals"),91},
+  { N_("Label"),   95},
+  { N_("Values"),  103},
+  { N_("Missing"), 95},
+  { N_("Columns"), 80},
+  { N_("Align"),   69},
+  { N_("Measure"), 99},
 };
 
 
-static gboolean
-click2row(GtkWidget *w, gint row, gpointer data)
-{
-  gint current_row, current_column;
-
-  select_sheet(PAGE_DATA_SHEET);
-  GtkWidget *data_sheet  = get_widget_assert(xml, "data_sheet");
 
-  gtk_sheet_get_active_cell(GTK_SHEET(data_sheet), 
-                           &current_row, &current_column);
-
-  gtk_sheet_set_active_cell(GTK_SHEET(data_sheet), current_row, row);
-
-  return FALSE;
-}
-
-
-
-const gchar *alignments[]={
-  _("Left"),
-  _("Right"),
-  _("Centre"),
+const gchar *const alignments[n_ALIGNMENTS + 1]={
+  N_("Left"),
+  N_("Right"),
+  N_("Centre"),
   0
 };
 
-const gchar *measures[]={
-  _("Nominal"),
-  _("Ordinal"),
-  _("Scale"),
+const gchar *const measures[n_MEASURES + 1]={
+  N_("Nominal"),
+  N_("Ordinal"),
+  N_("Scale"),
   0
 };
 
 static GtkListStore *
-create_label_list(const gchar **labels)
+create_label_list (const gchar *const *labels)
 {
+  const gchar *s;
   gint i = 0;
   GtkTreeIter iter;
 
   GtkListStore *list_store;
   list_store = gtk_list_store_new (1, G_TYPE_STRING);
 
-  const gchar *s;
+
   while ( (s = labels[i++]))
     {
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
-                         0, s,
+                         0, gettext (s),
                          -1);
     }
-       
+
   return list_store;
 }
 
-/* Callback for when the alignment combo box 
+/* Callback for when the alignment combo box
    item is selected */
-static void        
-change_alignment(GtkComboBox *cb,
+static void
+change_alignment (GtkComboBox *cb,
     gpointer user_data)
 {
-  struct PsppireVariable *pv = user_data;
-  gint active_item = gtk_combo_box_get_active(cb);
+  struct variable *pv = user_data;
+  gint active_item = gtk_combo_box_get_active (cb);
 
   if ( active_item < 0 ) return ;
 
-  psppire_variable_set_alignment(pv, active_item);
+  var_set_alignment (pv, active_item);
 }
 
 
 
-/* Callback for when the measure combo box 
+/* Callback for when the measure combo box
    item is selected */
-static void        
-change_measure(GtkComboBox *cb,
+static void
+change_measure (GtkComboBox *cb,
     gpointer user_data)
 {
-  struct PsppireVariable *pv = user_data;
-  gint active_item = gtk_combo_box_get_active(cb);
+  struct variable *pv = user_data;
+  gint active_item = gtk_combo_box_get_active (cb);
 
   if ( active_item < 0 ) return ;
 
-  psppire_variable_set_measure(pv, active_item);
+  var_set_measure (pv, active_item);
 }
 
 
 
-static gboolean 
-traverse_cell_callback (GtkSheet * sheet, 
-                       gint row, gint column, 
+static gboolean
+traverse_cell_callback (GtkSheet * sheet,
+                       gint row, gint column,
                        gint *new_row, gint *new_column
                        )
 {
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE(gtk_sheet_get_model(sheet));
+  PsppireVarStore *var_store = PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet));
 
-  gint n_vars = psppire_var_store_get_var_cnt(var_store);
+  gint n_vars = psppire_var_store_get_var_cnt (var_store);
 
   if ( row == n_vars && *new_row >= n_vars)
     {
-      GtkEntry *entry = GTK_ENTRY(gtk_sheet_get_entry(sheet));
+      GtkEntry *entry = GTK_ENTRY (gtk_sheet_get_entry (sheet));
 
-      const gchar *name = gtk_entry_get_text(entry);
+      const gchar *name = gtk_entry_get_text (entry);
 
-      if (! psppire_dict_check_name(var_store->dict, name, TRUE))
+      if (! psppire_dict_check_name (var_store->dict, name, TRUE))
        return FALSE;
-      
-      psppire_dict_insert_variable(var_store->dict, row, name);
+
+      psppire_dict_insert_variable (var_store->dict, row, name);
 
       return TRUE;
     }
 
   /* If the destination cell is outside the current  variables, then
-     accept the destination only as the name column of the first blank row
+     automatically create variables for the new rows.
   */
-  if ( *new_row > n_vars) 
-    return FALSE;
-  
-  if ( *new_row >= n_vars && *new_column != COL_NAME) 
-    return FALSE;
+  if ( (*new_row > n_vars) ||
+       (*new_row == n_vars && *new_column != COL_NAME) )
+    {
+      gint i;
+      for ( i = n_vars ; i <= *new_row; ++i )
+       psppire_dict_insert_variable (var_store->dict, i, NULL);
+    }
 
   return TRUE;
 }
 
 
-/* Callback whenever the cell on the var sheet is entered or left.
-   It sets the entry box type appropriately.
+
+
+/*
+   Callback whenever the cell on the var sheet is left
+*/
+static gboolean
+var_sheet_cell_entry_leave (GtkSheet * sheet, gint row, gint column,
+                           gpointer data)
+{
+  gtk_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
+  return TRUE;
+}
+
+
+
+/*
+   Callback whenever the cell on the var sheet is entered.
 */
-static gboolean 
-var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column, 
-                            gpointer leaving)
+static gboolean
+var_sheet_cell_entry_enter (GtkSheet * sheet, gint row, gint column,
+                           gpointer data)
 {
-  g_return_val_if_fail(sheet != NULL, FALSE);
+  GtkSheetCellAttr attributes;
+  PsppireVarStore *var_store ;
+  struct variable *pv ;
+
+  GladeXML *xml;
+
+  g_return_val_if_fail (sheet != NULL, FALSE);
+
+  var_store = PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet));
 
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE(gtk_sheet_get_model(sheet));
+  g_assert (var_store);
 
-  if ( row >= psppire_var_store_get_var_cnt(var_store))
+  if ( row >= psppire_var_store_get_var_cnt (var_store))
     return TRUE;
 
-  if ( leaving ) 
-    {
-      gtk_sheet_change_entry(sheet, GTK_TYPE_ENTRY);
-      return TRUE;
-    }
+  xml = glade_xml_new (PKGDATADIR "/data-editor.glade", NULL, NULL);
 
-  GtkSheetCellAttr attributes;
-  gtk_sheet_get_attributes(sheet, row, column, &attributes);
+  gtk_sheet_get_attributes (sheet, row, column, &attributes);
 
-  struct PsppireVariable *pv = psppire_var_store_get_variable(var_store, row);
+  pv = psppire_var_store_get_var (var_store, row);
 
   switch (column)
     {
@@ -230,41 +234,41 @@ var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column,
       {
        static GtkListStore *list_store = 0;
        GtkComboBoxEntry *cbe;
-       gtk_sheet_change_entry(sheet, GTK_TYPE_COMBO_BOX_ENTRY);
-       cbe = 
-         GTK_COMBO_BOX_ENTRY(gtk_sheet_get_entry(sheet)->parent);
+       gtk_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
+       cbe =
+         GTK_COMBO_BOX_ENTRY (gtk_sheet_get_entry (sheet)->parent);
 
 
-       if ( ! list_store) list_store = create_label_list(alignments);
+       if ( ! list_store) list_store = create_label_list (alignments);
 
-       gtk_combo_box_set_model(GTK_COMBO_BOX(cbe), 
-                               GTK_TREE_MODEL(list_store));
+       gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
+                               GTK_TREE_MODEL (list_store));
 
        gtk_combo_box_entry_set_text_column (cbe, 0);
 
 
-       g_signal_connect(G_OBJECT(cbe),"changed", 
-                        G_CALLBACK(change_alignment), pv);
+       g_signal_connect (G_OBJECT (cbe),"changed",
+                        G_CALLBACK (change_alignment), pv);
       }
       break;
     case COL_MEASURE:
       {
        static GtkListStore *list_store = 0;
        GtkComboBoxEntry *cbe;
-       gtk_sheet_change_entry(sheet, GTK_TYPE_COMBO_BOX_ENTRY);
-       cbe = 
-         GTK_COMBO_BOX_ENTRY(gtk_sheet_get_entry(sheet)->parent);
+       gtk_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
+       cbe =
+         GTK_COMBO_BOX_ENTRY (gtk_sheet_get_entry (sheet)->parent);
 
 
-       if ( ! list_store) list_store = create_label_list(measures);
+       if ( ! list_store) list_store = create_label_list (measures);
 
-       gtk_combo_box_set_model(GTK_COMBO_BOX(cbe), 
-                               GTK_TREE_MODEL(list_store));
+       gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
+                               GTK_TREE_MODEL (list_store));
 
        gtk_combo_box_entry_set_text_column (cbe, 0);
 
-       g_signal_connect(G_OBJECT(cbe),"changed", 
-                        G_CALLBACK(change_measure), pv);
+       g_signal_connect (G_OBJECT (cbe),"changed",
+                         G_CALLBACK (change_measure), pv);
       }
       break;
 
@@ -274,20 +278,20 @@ var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column,
 
        PsppireCustomEntry *customEntry;
 
-       gtk_sheet_change_entry(sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+       gtk_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
 
-       customEntry = 
-         PSPPIRE_CUSTOM_ENTRY(gtk_sheet_get_entry(sheet));
+       customEntry =
+         PSPPIRE_CUSTOM_ENTRY (gtk_sheet_get_entry (sheet));
 
 
-       if (!val_labs_dialog ) 
-           val_labs_dialog = val_labs_dialog_create(xml);
+       if (!val_labs_dialog )
+           val_labs_dialog = val_labs_dialog_create (xml);
 
-       val_labs_dialog->pv = pv;
+       val_labs_dialog_set_target_variable (val_labs_dialog, pv);
 
-       g_signal_connect_swapped(GTK_OBJECT(customEntry),
+       g_signal_connect_swapped (GTK_OBJECT (customEntry),
                                 "clicked",
-                                GTK_SIGNAL_FUNC(val_labs_dialog_show),
+                                GTK_SIGNAL_FUNC (val_labs_dialog_show),
                                 val_labs_dialog);
       }
       break;
@@ -295,20 +299,20 @@ var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column,
       {
        static struct missing_val_dialog *missing_val_dialog = 0;
        PsppireCustomEntry *customEntry;
-       
-       gtk_sheet_change_entry(sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
 
-       customEntry = 
-         PSPPIRE_CUSTOM_ENTRY(gtk_sheet_get_entry(sheet));
+       gtk_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+
+       customEntry =
+         PSPPIRE_CUSTOM_ENTRY (gtk_sheet_get_entry (sheet));
 
-       if (!missing_val_dialog ) 
-           missing_val_dialog = missing_val_dialog_create(xml);
+       if (!missing_val_dialog )
+           missing_val_dialog = missing_val_dialog_create (xml);
 
-       missing_val_dialog->pv = psppire_var_store_get_variable(var_store, row);
+       missing_val_dialog->pv = psppire_var_store_get_var (var_store, row);
 
-       g_signal_connect_swapped(GTK_OBJECT(customEntry),
+       g_signal_connect_swapped (GTK_OBJECT (customEntry),
                                 "clicked",
-                                GTK_SIGNAL_FUNC(missing_val_dialog_show),
+                                GTK_SIGNAL_FUNC (missing_val_dialog_show),
                                 missing_val_dialog);
       }
       break;
@@ -319,22 +323,22 @@ var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column,
 
        PsppireCustomEntry *customEntry;
 
-       gtk_sheet_change_entry(sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
+       gtk_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
 
-       customEntry = 
-         PSPPIRE_CUSTOM_ENTRY(gtk_sheet_get_entry(sheet));
+       customEntry =
+         PSPPIRE_CUSTOM_ENTRY (gtk_sheet_get_entry (sheet));
 
 
        /* Popup the Variable Type dialog box */
-       if (!var_type_dialog ) 
-           var_type_dialog = var_type_dialog_create(xml);
+       if (!var_type_dialog )
+           var_type_dialog = var_type_dialog_create (xml);
 
 
        var_type_dialog->pv = pv;
 
-       g_signal_connect_swapped(GTK_OBJECT(customEntry),
+       g_signal_connect_swapped (GTK_OBJECT (customEntry),
                                 "clicked",
-                                GTK_SIGNAL_FUNC(var_type_dialog_show),
+                                GTK_SIGNAL_FUNC (var_type_dialog_show),
                                 var_type_dialog);
       }
       break;
@@ -342,108 +346,121 @@ var_sheet_cell_change_entry (GtkSheet * sheet, gint row, gint column,
     case COL_DECIMALS:
     case COL_COLUMNS:
       {
-       if ( attributes.is_editable) 
+       if ( attributes.is_editable)
          {
            gint r_min, r_max;
 
-           const gchar *s = gtk_sheet_cell_get_text(sheet, row, column);
-
-           if (!s) 
-             return FALSE;
+           const gchar *s = gtk_sheet_cell_get_text (sheet, row, column);
 
-           const gint current_value  = atoi(s);
-
-           const struct fmt_spec *fmt = psppire_variable_get_write_spec(pv);
-           switch (column) 
+           if (s)
              {
-             case COL_WIDTH:
-               r_min = fmt->d + 1;
-               r_max = (psppire_variable_get_type(pv) == ALPHA) ? 255 : 40;
-               break;
-             case COL_DECIMALS:
-               r_min = 0 ; 
-               r_max = min(fmt->w - 1, 16);
-               break;
-             case COL_COLUMNS:
-               r_min = 1;
-               r_max = 255 ; /* Is this a sensible value ? */
-               break;
-             default:
-               g_assert_not_reached();
+               GtkSpinButton *spinButton ;
+               const gint current_value  = atoi (s);
+               GtkObject *adj ;
+
+               const struct fmt_spec *fmt = var_get_write_format (pv);
+               switch (column)
+                 {
+                 case COL_WIDTH:
+                   r_min = MAX (fmt->d + 1, fmt_min_output_width (fmt->type));
+                   r_max = fmt_max_output_width (fmt->type);
+                   break;
+                 case COL_DECIMALS:
+                   r_min = 0 ;
+                   r_max = fmt_max_output_decimals (fmt->type, fmt->w);
+                   break;
+                 case COL_COLUMNS:
+                   r_min = 1;
+                   r_max = 255 ; /* Is this a sensible value ? */
+                   break;
+                 default:
+                   g_assert_not_reached ();
+                 }
+
+               adj = gtk_adjustment_new (current_value,
+                                        r_min, r_max,
+                                        1.0, 1.0, 1.0 /* steps */
+                                        );
+
+               gtk_sheet_change_entry (sheet, GTK_TYPE_SPIN_BUTTON);
+
+               spinButton =
+                 GTK_SPIN_BUTTON (gtk_sheet_get_entry (sheet));
+
+               gtk_spin_button_set_adjustment (spinButton, GTK_ADJUSTMENT (adj));
+               gtk_spin_button_set_digits (spinButton, 0);
              }
-
-           GtkObject *adj =  
-             gtk_adjustment_new(current_value,
-                                r_min, r_max,
-                                1.0, 1.0, 1.0 /* steps */
-                                );
-
-           gtk_sheet_change_entry(sheet, GTK_TYPE_SPIN_BUTTON);
-
-           GtkSpinButton *spinButton = 
-             GTK_SPIN_BUTTON(gtk_sheet_get_entry(sheet));
-
-           gtk_spin_button_set_adjustment(spinButton, GTK_ADJUSTMENT(adj));
-           gtk_spin_button_set_digits(spinButton, 0);
          }
       }
-      break; 
+      break;
 
     default:
-      gtk_sheet_change_entry(sheet, GTK_TYPE_ENTRY);
+      gtk_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
       break;
     }
 
+
+  g_object_unref (xml);
+
   return TRUE;
 }
 
 
+extern PsppireVarStore *the_var_store;
+
 
 /* Create the var sheet */
-GtkWidget*
-psppire_variable_sheet_create (gchar *widget_name, 
-                              gchar *string1, 
+G_MODULE_EXPORT GtkWidget*
+psppire_variable_sheet_create (gchar *widget_name,
+                              gchar *string1,
                               gchar *string2,
                               gint int1, gint int2)
 {
+  gchar *codeset;
   gint i;
   GtkWidget *sheet;
 
-  GObject *geo = g_sheet_hetero_column_new(75, n_COLS);
-  GObject *row_geometry = g_sheet_uniform_row_new(25, n_initial_rows); 
+  GObject *geo = g_sheet_hetero_column_new (75, n_COLS);
 
+  g_assert (the_var_store);
 
+  sheet = gtk_sheet_new (G_SHEET_ROW (the_var_store),
+                       G_SHEET_COLUMN (geo),
+                       "variable sheet", 0);
 
-  sheet = gtk_sheet_new(G_SHEET_ROW(row_geometry),
-                       G_SHEET_COLUMN(geo), 
-                       "variable sheet", 0); 
 
   g_signal_connect (GTK_OBJECT (sheet), "activate",
-                   GTK_SIGNAL_FUNC (var_sheet_cell_change_entry),
+                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_enter),
                    0);
 
   g_signal_connect (GTK_OBJECT (sheet), "deactivate",
-                   GTK_SIGNAL_FUNC (var_sheet_cell_change_entry),
-                   (void *) 1);
+                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_leave),
+                   0);
 
   g_signal_connect (GTK_OBJECT (sheet), "traverse",
                    GTK_SIGNAL_FUNC (traverse_cell_callback), 0);
 
 
-  g_signal_connect (GTK_OBJECT (sheet), "double-click-row",
-                   GTK_SIGNAL_FUNC (click2row),
-                   sheet);
+  gtk_sheet_set_model (GTK_SHEET (sheet), G_SHEET_MODEL (the_var_store));
 
-  for (i = 0 ; i < n_COLS ; ++i ) 
+
+  /* Since this happens inside glade_xml_new, we must prevent strings from
+   * being re-encoded twice */
+  codeset = bind_textdomain_codeset (PACKAGE, 0);
+  bind_textdomain_codeset (PACKAGE, locale_charset ());
+
+  for (i = 0 ; i < n_COLS ; ++i )
     {
-      g_sheet_hetero_column_set_button_label(G_SHEET_HETERO_COLUMN(geo), i, 
-                                              column_def[i].label);
+      g_sheet_hetero_column_set_button_label (G_SHEET_HETERO_COLUMN (geo), i,
+                       gettext (column_def[i].label));
 
-      g_sheet_hetero_column_set_width(G_SHEET_HETERO_COLUMN(geo), i, 
+      g_sheet_hetero_column_set_width (G_SHEET_HETERO_COLUMN (geo), i,
                                               column_def[i].width);
     }
 
-  gtk_widget_show(sheet);
+  bind_textdomain_codeset (PACKAGE, codeset);
+
+  gtk_widget_show (sheet);
 
   return sheet;
 }