var-type-dialog: Change entries to spin buttons, add validation.
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 30 Jul 2012 06:56:09 +0000 (23:56 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 31 Jul 2012 05:57:33 +0000 (22:57 -0700)
The GtkEntry boxes used for entering and displaying width and
decimal places didn't do any validation that the width and decimal
places were valid for the selected format type, so it was possible
to enter values that couldn't actually be used.  This commit changes
the GtkEntry boxes into GtkSpinButton widgets that, as a side
effect, validate correct values through their attached
GtkAdjustments.  This is not just safer but easier to use.

src/ui/gui/var-type-dialog.c
src/ui/gui/var-type-dialog.h
src/ui/gui/var-type-dialog.ui

index 3449e8233a45cd2a65baa96fac140b0ff3ab5a4f..f5533b46115e8503c90a42bd40c2600ca25c56ea 100644 (file)
@@ -90,6 +90,8 @@ static void update_width_decimals (const struct var_type_dialog *);
 static void refresh_active_button (struct var_type_dialog *);
 static void on_active_button_change (GtkToggleButton *,
                                      struct var_type_dialog *);
+static void on_width_changed (GtkEntry *, struct var_type_dialog *);
+static void on_decimals_changed (GtkEntry *, struct var_type_dialog *);
 
 /* callback for when any of the radio buttons are toggled */
 static void
@@ -124,6 +126,26 @@ refresh_active_button (struct var_type_dialog *dialog)
   g_return_if_reached ();
 }
 
+static void
+update_adj_ranges (struct var_type_dialog *dialog)
+{
+  enum fmt_type type = dialog->fmt_l.type;
+  const enum fmt_use use = FMT_FOR_OUTPUT;
+  int min_w = fmt_min_width (type, use);
+  int max_w = fmt_max_width (type, use);
+  int max_d = fmt_max_decimals (type, max_w, use);
+
+  g_object_set (dialog->adj_width,
+                "lower", (double) min_w,
+                "upper", (double) max_w,
+                NULL);
+
+  g_object_set (dialog->adj_decimals,
+                "lower", 0.0,
+                "upper", (double) max_d,
+                NULL);
+}
+
 /* callback for when any of the radio buttons are toggled */
 static void
 on_active_button_change (GtkToggleButton *togglebutton,
@@ -221,6 +243,7 @@ on_active_button_change (GtkToggleButton *togglebutton,
     }
 
   fmt_fix_output (&dialog->fmt_l);
+  update_adj_ranges (dialog);
   update_width_decimals (dialog);
 }
 
@@ -242,16 +265,24 @@ add_to_group (GtkWidget *w, gpointer data)
 static void
 update_width_decimals (const struct var_type_dialog *dialog)
 {
-  gchar *text;
-  g_assert (dialog);
+  gtk_adjustment_set_value (dialog->adj_width, dialog->fmt_l.w);
+  gtk_adjustment_set_value (dialog->adj_decimals, dialog->fmt_l.d);
+}
 
-  text = g_strdup_printf ("%d", dialog->fmt_l.w);
-  gtk_entry_set_text (GTK_ENTRY (dialog->entry_width), text);
-  g_free (text);
+static void
+on_width_changed (GtkEntry *entry, struct var_type_dialog *dialog)
+{
+  int w = atoi (gtk_entry_get_text (GTK_ENTRY (dialog->entry_width)));
+  fmt_change_width (&dialog->fmt_l, w, FMT_FOR_OUTPUT);
+  update_width_decimals (dialog);
+}
 
-  text = g_strdup_printf ("%d", dialog->fmt_l.d);
-  gtk_entry_set_text (GTK_ENTRY (dialog->entry_decimals), text);
-  g_free (text);
+static void
+on_decimals_changed (GtkEntry *entry, struct var_type_dialog *dialog)
+{
+  int d = atoi (gtk_entry_get_text (GTK_ENTRY (dialog->entry_decimals)));
+  fmt_change_decimals (&dialog->fmt_l, d, FMT_FOR_OUTPUT);
+  update_width_decimals (dialog);
 }
 
 /* Callback for when the custom treeview row is changed.
@@ -329,7 +360,7 @@ set_date_format_from_treeview (GtkTreeView *treeview,
    It sets the fmt_l_spec to reflect the selected format */
 static void
 set_dollar_format_from_treeview (GtkTreeView *treeview,
-                               struct var_type_dialog *dialog)
+                                 struct var_type_dialog *dialog)
 {
   dialog->fmt_l = dollar_format[get_index_from_treeview (treeview)];
 }
@@ -341,6 +372,9 @@ set_custom_format_from_treeview (GtkTreeView *treeview,
                                  struct var_type_dialog *dialog)
 {
   dialog->fmt_l.type = cc_format[get_index_from_treeview (treeview)];
+  update_adj_ranges (dialog);
+  fmt_fix_output (&dialog->fmt_l);
+  update_width_decimals (dialog);
 }
 
 /* Create the structure */
@@ -384,13 +418,16 @@ var_type_dialog_create (GtkWindow *toplevel)
   dialog->width_decimals = get_widget_assert (xml, "width_decimals");
   dialog->label_decimals = get_widget_assert (xml, "decimals_label");
   dialog->entry_decimals = get_widget_assert (xml, "decimals_entry");
+  dialog->adj_decimals = gtk_spin_button_get_adjustment (
+    GTK_SPIN_BUTTON (dialog->entry_decimals));
 
   dialog->label_psample = get_widget_assert (xml, "psample_label");
   dialog->label_nsample = get_widget_assert (xml, "nsample_label");
 
 
   dialog->entry_width = get_widget_assert (xml,"width_entry");
-
+  dialog->adj_width = gtk_spin_button_get_adjustment (
+    GTK_SPIN_BUTTON (dialog->entry_width));
   dialog->custom_currency_hbox = get_widget_assert (xml,
                                                   "custom_currency_hbox");
 
@@ -442,7 +479,7 @@ var_type_dialog_create (GtkWindow *toplevel)
                               column);
 
 
-  list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+  list_store = gtk_list_store_new (1, G_TYPE_STRING);
 
   for ( i = 0 ; i < sizeof (date_format) / sizeof (date_format[0]) ; ++i )
     {
@@ -450,7 +487,6 @@ var_type_dialog_create (GtkWindow *toplevel)
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
                           0, fmt_date_template (f->type, f->w),
-                         1, f,
                          -1);
     }
 
@@ -477,8 +513,7 @@ var_type_dialog_create (GtkWindow *toplevel)
                               column);
 
 
-  list_store = gtk_list_store_new (2, G_TYPE_STRING,
-                                                G_TYPE_POINTER);
+  list_store = gtk_list_store_new (1, G_TYPE_STRING);
 
   for ( i = 0 ; i < sizeof (dollar_format)/sizeof (dollar_format[0]) ; ++i )
     {
@@ -486,7 +521,6 @@ var_type_dialog_create (GtkWindow *toplevel)
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
                           0, template,
-                         1, &dollar_format[i],
                          -1);
       free (template);
     }
@@ -519,7 +553,7 @@ var_type_dialog_create (GtkWindow *toplevel)
                               column);
 
 
-  list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+  list_store = gtk_list_store_new (1, G_TYPE_STRING);
 
   for ( i = 0 ; i < 5 ; ++i )
     {
@@ -527,7 +561,6 @@ var_type_dialog_create (GtkWindow *toplevel)
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
                           0, fmt_name (cc_fmts[i]),
-                         1, cc_format[i],
                          -1);
     }
 
@@ -547,6 +580,11 @@ var_type_dialog_create (GtkWindow *toplevel)
                   G_CALLBACK (preview_custom), dialog);
 
 
+  g_signal_connect (dialog->entry_width, "changed",
+                    G_CALLBACK (on_width_changed), dialog);
+  g_signal_connect (dialog->entry_decimals, "changed",
+                    G_CALLBACK (on_decimals_changed), dialog);
+
   g_signal_connect (dialog->entry_width,
                   "changed",
                   G_CALLBACK (preview_custom), dialog);
@@ -687,21 +725,6 @@ var_type_dialog_show (struct var_type_dialog *dialog)
   gtk_widget_show (dialog->window);
 }
 
-/* Fills F with an output format specification with type TYPE, width
-   W, and D decimals. Iff it's a valid format, then return true.
-*/
-static bool
-make_output_format_try (struct fmt_spec *f, int type, int w, int d)
-{
-  f->type = type;
-  f->w = w;
-  f->d = d;
-  return fmt_check_output (f);
-}
-
-
-
-
 /* Callbacks for the Variable Type Dialog Box */
 
 /* Callback for when the var type dialog is closed using the OK button.
@@ -711,60 +734,9 @@ on_var_type_ok_clicked (GtkWidget *w, gpointer data)
 {
   struct var_type_dialog *dialog = data;
 
-  g_assert (dialog);
-  g_assert (dialog->pv);
+  var_set_width (dialog->pv, fmt_var_width (&dialog->fmt_l));
+  var_set_both_formats (dialog->pv, &dialog->fmt_l);
 
-  {
-    gint width = atoi (gtk_entry_get_text
-                     (GTK_ENTRY (dialog->entry_width)));
-
-    gint decimals = atoi (gtk_entry_get_text
-                        (GTK_ENTRY (dialog->entry_decimals)));
-
-    gint new_width = 0;
-    bool result = false;
-    struct fmt_spec spec;
-    switch (dialog->active_button)
-      {
-      case BUTTON_STRING:
-       new_width = width;
-       result = make_output_format_try (&spec, FMT_A, width, 0);
-       break;
-      case BUTTON_NUMERIC:
-       result = make_output_format_try (&spec, FMT_F, width, decimals);
-       break;
-      case BUTTON_COMMA:
-       result = make_output_format_try (&spec, FMT_COMMA, width, decimals);
-       break;
-      case BUTTON_DOT:
-       result = make_output_format_try (&spec, FMT_DOT, width, decimals);
-       break;
-      case BUTTON_SCIENTIFIC:
-       result = make_output_format_try (&spec, FMT_E, width, decimals);
-       break;
-      case BUTTON_DATE:
-      case BUTTON_CUSTOM:
-       if  (! fmt_check_output (&dialog->fmt_l))
-         g_critical ("Invalid variable format");
-       else
-         result = memcpy (&spec, &dialog->fmt_l, sizeof (struct fmt_spec));
-       break;
-      case BUTTON_DOLLAR:
-       result = make_output_format_try (&spec, FMT_DOLLAR, width, decimals);
-       break;
-      default:
-       g_critical ("Unknown variable type: %d", dialog->active_button) ;
-       result = false;
-       break;
-      }
-
-    if ( result == true )
-      {
-       var_set_width (dialog->pv, new_width);
-       var_set_both_formats (dialog->pv, &spec);
-      }
-
-  }
   gtk_widget_hide (dialog->window);
 
   return FALSE;
index e194771667e73fe5840d57de84f1aa5419744815..d8c499f45d0d39d0eb0ca5ac2fbb82885a371b3b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2011  Free Software Foundation
+   Copyright (C) 2005, 2011, 2012  Free Software Foundation
 
    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
@@ -56,9 +56,11 @@ struct var_type_dialog
   /* Decimals */
   GtkWidget *label_decimals;
   GtkWidget *entry_decimals;
+  GtkAdjustment *adj_decimals;
 
   /* Width */
   GtkWidget *entry_width;
+  GtkAdjustment *adj_width;
 
   /* Container for width/decimals entry/labels */
   GtkWidget *width_decimals;
index 12edafd87f108f5f7f191e9ef4f32aecb5ed5948..d5cd681884a331f105919cbfab0ff5d51b6b3b52 100644 (file)
@@ -2,6 +2,20 @@
 <interface>
   <!-- interface-requires gtk+ 2.12 -->
   <!-- interface-naming-policy project-wide -->
+  <object class="GtkAdjustment" id="adj_width">
+    <property name="value">1</property>
+    <property name="lower">1</property>
+    <property name="upper">40</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="adj_decimals">
+    <property name="value">0</property>
+    <property name="lower">0</property>
+    <property name="upper">40</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
   <object class="GtkWindow" id="var_type_dialog">
     <property name="border_width">6</property>
     <property name="title" translatable="yes">Variable Type</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkEntry" id="decimals_entry">
+                  <object class="GtkSpinButton" id="decimals_entry">
                     <property name="width_request">25</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                   <property name="digits">0</property>
+                   <property name="numeric">True</property>
+                   <property name="adjustment">adj_decimals</property>
                   </object>
                   <packing>
                     <property name="left_attach">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkEntry" id="width_entry">
+                  <object class="GtkSpinButton" id="width_entry">
                     <property name="width_request">25</property>
                     <property name="can_focus">True</property>
+                   <property name="digits">0</property>
+                   <property name="numeric">True</property>
+                   <property name="adjustment">adj_width</property>
                   </object>
                   <packing>
                     <property name="left_attach">1</property>