psppire_data_window: Don't crash when trying to delete cases when none are selected
[pspp] / src / ui / gui / psppire-variable-sheet.c
index 7af764d7c9e6b94bfc6be8d99c38cbf3eed9dd2e..35ee7d6085d636083ae072f99be88ce8654bb799 100644 (file)
 #define P_(X) (X)
 
 
-G_DEFINE_TYPE (PsppireVariableSheet, psppire_variable_sheet, JMD_TYPE_SHEET)
+G_DEFINE_TYPE (PsppireVariableSheet, psppire_variable_sheet, SSW_TYPE_SHEET)
 
 static void
-set_var_type (GtkCellRenderer *renderer,
-     GtkCellEditable *editable,
-     gchar           *path,
-     gpointer         user_data)
+set_var_type (PsppireVariableSheet *sheet)
 {
-  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
   gint row = -1, col = -1;
-  jmd_sheet_get_active_cell (JMD_SHEET (sheet), &col, &row);
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
 
   PsppireDict *dict = NULL;
   g_object_get (sheet, "data-model", &dict, NULL);
@@ -62,14 +58,10 @@ set_var_type (GtkCellRenderer *renderer,
 }
 
 static void
-set_missing_values (GtkCellRenderer *renderer,
-     GtkCellEditable *editable,
-     gchar           *path,
-     gpointer         user_data)
+set_missing_values (PsppireVariableSheet *sheet)
 {
-  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
   gint row = -1, col = -1;
-  jmd_sheet_get_active_cell (JMD_SHEET (sheet), &col, &row);
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
 
   PsppireDict *dict = NULL;
   g_object_get (sheet, "data-model", &dict, NULL);
@@ -89,14 +81,10 @@ set_missing_values (GtkCellRenderer *renderer,
 }
 
 static void
-set_value_labels (GtkCellRenderer *renderer,
-     GtkCellEditable *editable,
-     gchar           *path,
-     gpointer         user_data)
+set_value_labels (PsppireVariableSheet *sheet)
 {
-  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (user_data);
   gint row = -1, col = -1;
-  jmd_sheet_get_active_cell (JMD_SHEET (sheet), &col, &row);
+  ssw_sheet_get_active_cell (SSW_SHEET (sheet), &col, &row);
 
   PsppireDict *dict = NULL;
   g_object_get (sheet, "data-model", &dict, NULL);
@@ -213,8 +201,8 @@ select_renderer_func (PsppireVariableSheet *sheet, gint col, gint row, GType typ
 \f
 
 static void
-show_variables_row_popup (JmdSheet *sheet, int row, uint button,
-                         uint state, gpointer p)
+show_variables_row_popup (SswSheet *sheet, int row, guint button,
+                         guint state, gpointer p)
 {
   PsppireVariableSheet *var_sheet = PSPPIRE_VARIABLE_SHEET (sheet);
   GListModel *vmodel = NULL;
@@ -253,9 +241,9 @@ insert_new_variable_var (PsppireVariableSheet *var_sheet)
 
 
 static void
-delete_variables (JmdSheet *sheet)
+delete_variables (SswSheet *sheet)
 {
-  JmdRange *range = sheet->selection;
+  SswRange *range = sheet->selection;
 
   PsppireDict *dict = NULL;
   g_object_get (sheet, "data-model", &dict, NULL);
@@ -296,10 +284,10 @@ create_var_row_header_popup_menu (PsppireVariableSheet *var_sheet)
 
 
 static void
-set_var_popup_sensitivity (JmdSheet *sheet, gpointer selection, gpointer p)
+set_var_popup_sensitivity (SswSheet *sheet, gpointer selection, gpointer p)
 {
   PsppireVariableSheet *var_sheet = PSPPIRE_VARIABLE_SHEET (sheet);
-  JmdRange *range = selection;
+  SswRange *range = selection;
   gint width = gtk_tree_model_get_n_columns (sheet->data_model);
 
   gboolean whole_row_selected = (range->start_x == 0 &&
@@ -381,7 +369,7 @@ change_var_property (PsppireVariableSheet *var_sheet, gint col, gint row, const
 }
 
 static gchar *
-var_sheet_data_to_string (JmdSheet *sheet, GtkTreeModel *m,
+var_sheet_data_to_string (SswSheet *sheet, GtkTreeModel *m,
                          gint col, gint row, const GValue *in)
 {
   if (col >= n_DICT_COLS - 1) /* -1 because psppire-dict has an extra column */
@@ -413,7 +401,7 @@ var_sheet_data_to_string (JmdSheet *sheet, GtkTreeModel *m,
       return text;
     }
 
-  return jmd_sheet_default_forward_conversion (sheet, m, col, row, in);
+  return ssw_sheet_default_forward_conversion (sheet, m, col, row, in);
 }
 
 \f
@@ -438,6 +426,19 @@ psppire_variable_sheet_dispose (GObject *obj)
   G_OBJECT_CLASS (parent_class)->dispose (obj);
 }
 
+static void
+psppire_variable_sheet_finalize (GObject *object)
+{
+  PsppireVariableSheet *sheet = PSPPIRE_VARIABLE_SHEET (object);
+
+  g_free (sheet->value_label_dispatch);
+  g_free (sheet->missing_values_dispatch);
+  g_free (sheet->var_type_dispatch);
+  
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    (*G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
 static void
 psppire_variable_sheet_class_init (PsppireVariableSheetClass *class)
 {
@@ -445,6 +446,8 @@ psppire_variable_sheet_class_init (PsppireVariableSheetClass *class)
   object_class->dispose = psppire_variable_sheet_dispose;
 
   parent_class = g_type_class_peek_parent (class);
+
+  object_class->finalize = psppire_variable_sheet_finalize;
 }
 
 GtkWidget*
@@ -458,6 +461,8 @@ psppire_variable_sheet_new (void)
                  "select-renderer-func", select_renderer_func,
                  "hmodel", vsh,
                  "forward-conversion", var_sheet_data_to_string,
+                 "editable", TRUE,
+                 "vertical-draggable", TRUE,
                  NULL);
 
   return GTK_WIDGET (obj);
@@ -485,26 +490,96 @@ move_variable (PsppireVariableSheet *sheet, gint from, gint to, gpointer ud)
   dict_reorder_var (dict->dict, var, new_pos);
 }
 
+
+static gboolean
+is_printable_key (gint keyval)
+{
+  switch (keyval)
+    {
+    case GDK_KEY_Return:
+    case GDK_KEY_ISO_Left_Tab:
+    case GDK_KEY_Tab:
+      return FALSE;
+      break;
+    }
+  
+  return (0 != gdk_keyval_to_unicode (keyval));
+}
+
+struct dispatch
+{
+  PsppireVariableSheet *sheet;
+  void (*payload) (PsppireVariableSheet *);
+};
+
+
+static gboolean
+on_key_press (GtkWidget *w, GdkEventKey *e, gpointer user_data)
+{
+  const struct dispatch *d = user_data;
+  if (is_printable_key (e->keyval))
+    {
+      d->payload (d->sheet);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+on_button_press (GtkWidget *w, GdkEventButton *e, gpointer user_data)
+{
+  const struct dispatch *d = user_data;
+  if (e->button != 1)
+    return TRUE;
+
+  d->payload (d->sheet);
+  return TRUE;
+}
+  
+static void
+on_edit_start (GtkCellRenderer *renderer,
+     GtkCellEditable *editable,
+     gchar           *path,
+     gpointer         user_data)
+{
+  gtk_widget_grab_focus (GTK_WIDGET (editable));
+  g_signal_connect (editable, "key-press-event",
+                   G_CALLBACK (on_key_press), user_data);
+  g_signal_connect (editable, "button-press-event",
+                   G_CALLBACK (on_button_press), user_data);
+  
+}
+
 static void
 psppire_variable_sheet_init (PsppireVariableSheet *sheet)
 {
   sheet->dispose_has_run = FALSE;
 
   sheet->value_label_renderer = gtk_cell_renderer_text_new ();
-  g_signal_connect (sheet->value_label_renderer,
-                   "editing-started", G_CALLBACK (set_value_labels),
-                   sheet);
+  sheet->value_label_dispatch = g_malloc (sizeof *sheet->value_label_dispatch);
+  sheet->value_label_dispatch->sheet = sheet;
+  sheet->value_label_dispatch->payload = set_value_labels;
+  g_signal_connect_after (sheet->value_label_renderer,
+                         "editing-started", G_CALLBACK (on_edit_start),
+                         sheet->value_label_dispatch);
 
   sheet->missing_values_renderer = gtk_cell_renderer_text_new ();
-  g_signal_connect (sheet->missing_values_renderer,
-                   "editing-started", G_CALLBACK (set_missing_values),
-                   sheet);
+  sheet->missing_values_dispatch = g_malloc (sizeof *sheet->missing_values_dispatch);
+  sheet->missing_values_dispatch->sheet = sheet;
+  sheet->missing_values_dispatch->payload = set_missing_values;
+  g_signal_connect_after (sheet->missing_values_renderer,
+                         "editing-started", G_CALLBACK (on_edit_start),
+                         sheet->missing_values_dispatch);
 
   sheet->var_type_renderer = gtk_cell_renderer_text_new ();
-  g_signal_connect (sheet->var_type_renderer,
-                   "editing-started", G_CALLBACK (set_var_type),
-                   sheet);
-
+  sheet->var_type_dispatch = g_malloc (sizeof *sheet->var_type_dispatch);
+  sheet->var_type_dispatch->sheet = sheet;
+  sheet->var_type_dispatch->payload = set_var_type;
+  g_signal_connect_after (sheet->var_type_renderer,
+                         "editing-started", G_CALLBACK (on_edit_start),
+                         sheet->var_type_dispatch);
+  
   sheet->row_popup = create_var_row_header_popup_menu (sheet);