Cleanup gtksheet and add features to var-sheet.[ch]
[pspp-builds.git] / src / ui / gui / var-sheet.c
index 45111621dade6832b235cc58746fc1970d1a6502..ac6ce929049edea2659586876f004e631a6bce32 100644 (file)
@@ -1,10 +1,9 @@
-/*
-   PSPPIRE --- A Graphical User Interface for PSPP
-   Copyright (C) 2004, 2005, 2006  Free Software Foundation
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2004, 2005, 2006, 2007  Free Software Foundation
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -13,9 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
 /* This module creates the Variable Sheet used for inputing the
@@ -33,7 +30,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <langinfo.h>
 
 #include <data/value.h>
 
@@ -41,6 +37,8 @@
 #include <gtksheet/gsheet-hetero-column.h>
 #include <gtksheet/gsheet-uniform-row.h>
 
+#include "localcharset.h"
+#include "xalloc.h"
 #include "psppire-var-store.h"
 #include "helper.h"
 #include "psppire-dict.h"
@@ -81,7 +79,7 @@ static const struct column_parameters column_def[] = {
 const gchar *const alignments[n_ALIGNMENTS + 1]={
   N_("Left"),
   N_("Right"),
-  N_("Centre"),
+  N_("Center"),
   0
 };
 
@@ -92,8 +90,15 @@ const gchar *const measures[n_MEASURES + 1]={
   0
 };
 
+G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, GTK_TYPE_SHEET);
+
+static void
+psppire_var_sheet_class_init (PsppireVarSheetClass *class)
+{
+}
+
 static GtkListStore *
-create_label_list(const gchar **labels)
+create_label_list (const gchar *const *labels)
 {
   const gchar *s;
   gint i = 0;
@@ -107,7 +112,7 @@ create_label_list(const gchar **labels)
     {
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
-                         0, gettext(s),
+                         0, gettext (s),
                          -1);
     }
 
@@ -117,11 +122,11 @@ create_label_list(const gchar **labels)
 /* Callback for when the alignment combo box
    item is selected */
 static void
-change_alignment(GtkComboBox *cb,
+change_alignment (GtkComboBox *cb,
     gpointer user_data)
 {
   struct variable *pv = user_data;
-  gint active_item = gtk_combo_box_get_active(cb);
+  gint active_item = gtk_combo_box_get_active (cb);
 
   if ( active_item < 0 ) return ;
 
@@ -133,11 +138,11 @@ change_alignment(GtkComboBox *cb,
 /* Callback for when the measure combo box
    item is selected */
 static void
-change_measure(GtkComboBox *cb,
+change_measure (GtkComboBox *cb,
     gpointer user_data)
 {
   struct variable *pv = user_data;
-  gint active_item = gtk_combo_box_get_active(cb);
+  gint active_item = gtk_combo_box_get_active (cb);
 
   if ( active_item < 0 ) return ;
 
@@ -152,20 +157,24 @@ traverse_cell_callback (GtkSheet * sheet,
                        gint *new_row, gint *new_column
                        )
 {
-  PsppireVarStore *var_store = PSPPIRE_VAR_STORE(gtk_sheet_get_model(sheet));
+  PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (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 (*new_row >= n_vars && !var_sheet->may_create_vars)
+    return FALSE;
 
   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;
     }
@@ -178,7 +187,7 @@ traverse_cell_callback (GtkSheet * sheet,
     {
       gint i;
       for ( i = n_vars ; i <= *new_row; ++i )
-       psppire_dict_insert_variable(var_store->dict, i, NULL);
+       psppire_dict_insert_variable (var_store->dict, i, NULL);
     }
 
   return TRUE;
@@ -194,7 +203,7 @@ static gboolean
 var_sheet_cell_entry_leave (GtkSheet * sheet, gint row, gint column,
                            gpointer data)
 {
-  gtk_sheet_change_entry(sheet, GTK_TYPE_ENTRY);
+  gtk_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
   return TRUE;
 }
 
@@ -209,110 +218,121 @@ var_sheet_cell_entry_enter (GtkSheet * sheet, gint row, gint column,
 {
   GtkSheetCellAttr attributes;
   PsppireVarStore *var_store ;
-  struct variable *pv ;
+  struct variable *var ;
 
   GladeXML *xml;
 
-  g_return_val_if_fail(sheet != NULL, FALSE);
+  g_return_val_if_fail (sheet != NULL, FALSE);
 
-  var_store = PSPPIRE_VAR_STORE (gtk_sheet_get_model(sheet));
+  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;
 
-  xml = glade_xml_new (PKGDATADIR "/data-editor.glade", NULL, NULL);
+  xml = XML_NEW ("data-editor.glade");
 
-  gtk_sheet_get_attributes(sheet, row, column, &attributes);
+  gtk_sheet_get_attributes (sheet, row, column, &attributes);
 
-  pv = psppire_var_store_get_var (var_store, row);
+  var = psppire_var_store_get_var (var_store, row);
 
   switch (column)
     {
     case COL_ALIGN:
       {
-       static GtkListStore *list_store = 0;
+       static GtkListStore *list_store = NULL;
        GtkComboBoxEntry *cbe;
-       gtk_sheet_change_entry(sheet, GTK_TYPE_COMBO_BOX_ENTRY);
+       gtk_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
        cbe =
-         GTK_COMBO_BOX_ENTRY(gtk_sheet_get_entry(sheet)->parent);
+         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), var);
       }
       break;
+
     case COL_MEASURE:
       {
        static GtkListStore *list_store = 0;
        GtkComboBoxEntry *cbe;
-       gtk_sheet_change_entry(sheet, GTK_TYPE_COMBO_BOX_ENTRY);
+       gtk_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
        cbe =
-         GTK_COMBO_BOX_ENTRY(gtk_sheet_get_entry(sheet)->parent);
+         GTK_COMBO_BOX_ENTRY (gtk_sheet_get_entry (sheet)->parent);
 
 
        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), var);
       }
       break;
 
     case COL_VALUES:
       {
-       static struct val_labs_dialog *val_labs_dialog = 0;
+       static struct val_labs_dialog *val_labs_dialog = NULL;
 
        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));
+         PSPPIRE_CUSTOM_ENTRY (gtk_sheet_get_entry (sheet));
 
+       if ( var_is_long_string (var))
+         g_object_set (customEntry,
+                       "editable", FALSE,
+                       NULL);
 
        if (!val_labs_dialog )
-           val_labs_dialog = val_labs_dialog_create(xml);
+           val_labs_dialog = val_labs_dialog_create (xml);
 
-       val_labs_dialog->pv = pv;
+       val_labs_dialog_set_target_variable (val_labs_dialog, var);
 
-       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;
+
     case COL_MISSING:
       {
        static struct missing_val_dialog *missing_val_dialog = 0;
        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));
+         PSPPIRE_CUSTOM_ENTRY (gtk_sheet_get_entry (sheet));
+
+       if ( var_is_long_string (var))
+         g_object_set (customEntry,
+                       "editable", FALSE,
+                       NULL);
 
        if (!missing_val_dialog )
-           missing_val_dialog = missing_val_dialog_create(xml);
+           missing_val_dialog = missing_val_dialog_create (xml);
 
        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;
@@ -323,25 +343,26 @@ var_sheet_cell_entry_enter (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));
+         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);
+           var_type_dialog = var_type_dialog_create (xml);
 
 
-       var_type_dialog->pv = pv;
+       var_type_dialog->pv = var;
 
-       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;
+
     case COL_WIDTH:
     case COL_DECIMALS:
     case COL_COLUMNS:
@@ -350,15 +371,15 @@ var_sheet_cell_entry_enter (GtkSheet * sheet, gint row, gint column,
          {
            gint r_min, r_max;
 
-           const gchar *s = gtk_sheet_cell_get_text(sheet, row, column);
+           const gchar *s = gtk_sheet_cell_get_text (sheet, row, column);
 
            if (s)
              {
                GtkSpinButton *spinButton ;
-               const gint current_value  = atoi(s);
+               const gint current_value  = atoi (s);
                GtkObject *adj ;
 
-               const struct fmt_spec *fmt = var_get_write_format (pv);
+               const struct fmt_spec *fmt = var_get_write_format (var);
                switch (column)
                  {
                  case COL_WIDTH:
@@ -374,28 +395,28 @@ var_sheet_cell_entry_enter (GtkSheet * sheet, gint row, gint column,
                    r_max = 255 ; /* Is this a sensible value ? */
                    break;
                  default:
-                   g_assert_not_reached();
+                   g_assert_not_reached ();
                  }
 
-               adj = gtk_adjustment_new(current_value,
+               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);
+               gtk_sheet_change_entry (sheet, GTK_TYPE_SPIN_BUTTON);
 
                spinButton =
-                 GTK_SPIN_BUTTON(gtk_sheet_get_entry(sheet));
+                 GTK_SPIN_BUTTON (gtk_sheet_get_entry (sheet));
 
-               gtk_spin_button_set_adjustment(spinButton, GTK_ADJUSTMENT(adj));
-               gtk_spin_button_set_digits(spinButton, 0);
+               gtk_spin_button_set_adjustment (spinButton, GTK_ADJUSTMENT (adj));
+               gtk_spin_button_set_digits (spinButton, 0);
              }
          }
       }
       break;
 
     default:
-      gtk_sheet_change_entry(sheet, GTK_TYPE_ENTRY);
+      gtk_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
       break;
     }
 
@@ -405,62 +426,87 @@ var_sheet_cell_entry_enter (GtkSheet * sheet, gint row, gint column,
   return TRUE;
 }
 
+static void
+psppire_var_sheet_init (PsppireVarSheet *self)
+{
+  self->may_create_vars = true;
+
+  g_signal_connect (self, "activate",
+                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_enter),
+                   0);
 
-extern PsppireVarStore *the_var_store;
+  g_signal_connect (self, "deactivate",
+                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_leave),
+                   0);
 
+  g_signal_connect (self, "traverse",
+                   GTK_SIGNAL_FUNC (traverse_cell_callback), 0);
+}
 
-/* Create the var sheet */
-GtkWidget*
-psppire_variable_sheet_create (gchar *widget_name,
-                              gchar *string1,
-                              gchar *string2,
-                              gint int1, gint int2)
+GtkWidget *
+psppire_var_sheet_new_with_var_store (PsppireVarStore *var_store)
 {
-  gchar *codeset;
-  gint i;
   GtkWidget *sheet;
 
-  GObject *geo = g_sheet_hetero_column_new(75, n_COLS);
+  gint i;
 
-  g_assert (the_var_store);
+  GObject *geo = g_sheet_hetero_column_new (75, n_COLS);
+  g_assert (var_store);
 
-  sheet = gtk_sheet_new(G_SHEET_ROW(the_var_store),
-                       G_SHEET_COLUMN(geo),
-                       "variable sheet", 0);
+  sheet = g_object_new (PSPPIRE_TYPE_VAR_SHEET,
+                       "row-geometry", var_store,
+                       "column-geometry", geo,
+                       NULL);
 
+  gtk_sheet_set_model (GTK_SHEET (sheet), G_SHEET_MODEL (var_store));
 
-  g_signal_connect (GTK_OBJECT (sheet), "activate",
-                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_enter),
-                   0);
 
-  g_signal_connect (GTK_OBJECT (sheet), "deactivate",
-                   GTK_SIGNAL_FUNC (var_sheet_cell_entry_leave),
-                   0);
+  for (i = 0 ; i < n_COLS ; ++i )
+    {
+      g_sheet_hetero_column_set_button_label (G_SHEET_HETERO_COLUMN (geo), i,
+                       gettext (column_def[i].label));
 
-  g_signal_connect (GTK_OBJECT (sheet), "traverse",
-                   GTK_SIGNAL_FUNC (traverse_cell_callback), 0);
+      g_sheet_hetero_column_set_width (G_SHEET_HETERO_COLUMN (geo), i,
+                                              column_def[i].width);
+    }
 
 
-  gtk_sheet_set_model(sheet, G_SHEET_MODEL(the_var_store));
 
+  return sheet;
+}
+
+/* Create the var sheet */
+G_MODULE_EXPORT GtkWidget*
+psppire_variable_sheet_create (gchar *widget_name,
+                              gchar *string1,
+                              gchar *string2,
+                              gint int1, gint int2)
+{
+  gchar *codeset;
+  GtkWidget *sheet;
+  extern PsppireVarStore *the_var_store;
 
   /* 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, nl_langinfo(CODESET));
-  for (i = 0 ; i < n_COLS ; ++i )
-    {
-      g_sheet_hetero_column_set_button_label(G_SHEET_HETERO_COLUMN(geo), i,
-                       gettext(column_def[i].label));
+  codeset = xstrdup (bind_textdomain_codeset (PACKAGE, 0));
+  bind_textdomain_codeset (PACKAGE, locale_charset ());
 
-      g_sheet_hetero_column_set_width(G_SHEET_HETERO_COLUMN(geo), i,
-                                              column_def[i].width);
-    }
-  bind_textdomain_codeset(PACKAGE, codeset);
 
-  gtk_widget_show(sheet);
+  sheet = psppire_var_sheet_new_with_var_store (the_var_store);
+
+  bind_textdomain_codeset (PACKAGE, codeset);
+  free (codeset);
+
+  gtk_widget_show (sheet);
 
   return sheet;
 }
 
 
+
+void
+psppire_var_sheet_set_may_create_vars (PsppireVarSheet *sheet,
+                                       gboolean may_create_vars)
+{
+  sheet->may_create_vars = may_create_vars;
+}