Added the ability to resize string variables from the GUI. Thanks to
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 18 Jul 2007 00:50:58 +0000 (00:50 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Wed, 18 Jul 2007 00:50:58 +0000 (00:50 +0000)
Ben for his comments.

15 files changed:
src/data/ChangeLog
src/data/datasheet.c
src/data/dictionary.c
src/data/dictionary.h
src/data/vardict.h
src/data/variable.c
src/ui/gui/ChangeLog
src/ui/gui/helper.c
src/ui/gui/helper.h
src/ui/gui/psppire-case-file.c
src/ui/gui/psppire-case-file.h
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dict.h
src/ui/gui/psppire-var-store.c

index 26c751ab199d14cb3645639be23d2217ca657bc4..7d8ef4dde0bd2515d76b0e133b2dea2e0a662f75 100644 (file)
@@ -1,3 +1,16 @@
+2007-07-18 John Darrington <john@darrington.wattle.id.au>
+
+       * datasheet.c (datasheet_delete_columns): Added assertion to check
+       we're not deleting outside the range of the sheet.  
+
+       
+       * dictionary.c dictionary.h variable.c: Added the ability for string
+       variables to be resized.
+       
+       * vardict.h: Added some prototypes (moved from dictionary.h) as
+       these should only be called by variable.c
+
+
 2007-07-14 John Darrington <john@darrington.wattle.id.au>
 
        * sfm-reader.c: Respect case_cnt field in file header.
index 971144cb2305981646b346bd90effa07a5afcf27..913c8e5aff495f97055b8a7a62579716d3840f77 100644 (file)
@@ -354,6 +354,8 @@ datasheet_delete_columns (struct datasheet *ds, size_t start, size_t cnt)
 {
   size_t lcol;
 
+  assert ( start + cnt <= axis_get_size (ds->columns) );
+
   /* Free up columns for reuse. */
   for (lcol = start; lcol < start + cnt; lcol++)
     {
index d580474edced2e47bf6e4a01424b0a19f19f442c..44504ed96525ec5c4af0eaffd82f5de2fe3634c1 100644 (file)
@@ -156,14 +156,22 @@ dict_clear (struct dictionary *d)
 
   while (d->var_cnt > 0 )
     {
-      var_clear_vardict (d->var[d->var_cnt - 1]);
-      var_destroy (d->var[d->var_cnt -1]);
+      struct variable *v = d->var[d->var_cnt - 1];
+      int dict_index = var_get_dict_index (v);
+      int case_index = var_get_case_index (v);
+      int val_cnt = var_get_value_cnt (v);
+
+      var_clear_vardict (v);
+      var_destroy (v);
 
       d->var_cnt--;
 
       if (d->callbacks &&  d->callbacks->var_deleted )
-       d->callbacks->var_deleted (d, d->var_cnt, d->cb_data);
+       d->callbacks->var_deleted (d,
+                                  dict_index, case_index, val_cnt,
+                                  d->cb_data);
     }
+
   free (d->var);
   d->var = NULL;
   d->var_cnt = d->var_cap = 0;
@@ -418,7 +426,7 @@ set_var_dict_index (struct variable *v, int dict_index)
     d->callbacks->var_changed (d, dict_index, d->cb_data);
 }
 
-/* Sets the case_index in V's vardict to DICT_INDEX. */
+/* Sets the case_index in V's vardict to CASE_INDEX. */
 static void
 set_var_case_index (struct variable *v, int case_index)
 {
@@ -455,6 +463,8 @@ void
 dict_delete_var (struct dictionary *d, struct variable *v)
 {
   int dict_index = var_get_dict_index (v);
+  const int case_index = var_get_case_index (v);
+  const int val_cnt = var_get_value_cnt (v);
 
   assert (dict_contains_var (d, v));
 
@@ -487,7 +497,7 @@ dict_delete_var (struct dictionary *d, struct variable *v)
   var_destroy (v);
 
   if (d->callbacks &&  d->callbacks->var_deleted )
-    d->callbacks->var_deleted (d, dict_index, d->cb_data);
+    d->callbacks->var_deleted (d, dict_index, case_index, val_cnt, d->cb_data);
 }
 
 /* Deletes the COUNT variables listed in VARS from D.  This is
@@ -834,6 +844,33 @@ dict_compact_values (struct dictionary *d)
     }
 }
 
+
+/*
+   Reassigns case indices for D, increasing each index above START by
+   the value PADDING.
+*/
+static void
+dict_pad_values (struct dictionary *d, int start, int padding)
+{
+  size_t i;
+
+  if ( padding <= 0 ) 
+       return;
+
+  for (i = 0; i < d->var_cnt; ++i)
+    {
+      struct variable *v = d->var[i];
+
+      int index = var_get_case_index (v);
+
+      if ( index >= start)
+       set_var_case_index (v, index + padding);
+    }
+
+  d->next_value_idx += padding;
+}
+
+
 /* Returns the number of values that would be used by a case if
    dict_compact_values() were called. */
 size_t
@@ -1388,3 +1425,23 @@ dict_var_changed (const struct variable *v)
        d->callbacks->var_changed (d, var_get_dict_index (v), d->cb_data);
     }
 }
+
+
+/* Called from variable.c to notify the dictionary that the variable's width
+   has changed */
+void
+dict_var_resized (const struct variable *v, int delta)
+{
+  if ( var_has_vardict (v))
+    {
+      const struct vardict_info *vdi = var_get_vardict (v);
+      struct dictionary *d;
+
+      d = vdi->dict;
+
+      dict_pad_values (d, var_get_case_index(v) + 1, delta);
+
+      if ( d->callbacks && d->callbacks->var_resized )
+       d->callbacks->var_resized (d, var_get_dict_index (v), delta, d->cb_data);
+    }
+}
index 9dbd773370afaa2a60aa90f6ae63e778c44f7be7..4887a3102a368e3ff53125584f6051a48d3404be 100644 (file)
@@ -29,8 +29,9 @@ struct string;
 struct dict_callbacks
  {
   void (*var_added) (struct dictionary *, int, void *);
-  void (*var_deleted) (struct dictionary *, int, void *);
+  void (*var_deleted) (struct dictionary *, int, int, int, void *);
   void (*var_changed) (struct dictionary *, int, void *);
+  void (*var_resized) (struct dictionary *, int, int, void *);
   void (*weight_changed) (struct dictionary *, int, void *);
   void (*filter_changed) (struct dictionary *, int, void *);
   void (*split_changed) (struct dictionary *, void *);
@@ -148,7 +149,4 @@ void dict_clear_vectors (struct dictionary *);
 
 void dict_assign_short_names (struct dictionary *);
 
-/* Called only from variable.c */
-void dict_var_changed (const struct variable *v);
-
 #endif /* dictionary.h */
index 4e124afc6cf6440a9a3f9b32e43e95d65dbd781a..aaf8ba05e6573e9658640b4032402099d5365b87 100644 (file)
@@ -36,4 +36,9 @@ void var_set_vardict (struct variable *, const struct vardict_info *);
 bool var_has_vardict (const struct variable *);
 void var_clear_vardict (struct variable *);
 
+
+/* Called only from variable.c, but defined in dictionary.c */
+void dict_var_changed (const struct variable *v);
+void dict_var_resized (const struct variable *v, int delta);
+
 #endif /* data/vardict.h */
index aa65606f02652d826b976a7f0a423cfb3b16b3f9..a10a8adea7ec03cbf60fd7cde4633f8fa5c7c167 100644 (file)
@@ -29,6 +29,7 @@
 #include "value-labels.h"
 #include "vardict.h"
 
+#include <libpspp/misc.h>
 #include <libpspp/alloc.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
@@ -349,6 +350,7 @@ var_get_width (const struct variable *v)
 void
 var_set_width (struct variable *v, int new_width)
 {
+  const int old_width = v->width;
   enum var_type new_type = var_type_from_width (new_width);
 
   if (mv_is_resizable (&v->miss, new_width))
@@ -382,6 +384,14 @@ var_set_width (struct variable *v, int new_width)
 
   v->width = new_width;
 
+  {
+    const int old_val_count = value_cnt_from_width (old_width);
+    const int new_val_count = value_cnt_from_width (new_width);
+
+    if ( old_val_count != new_val_count)
+        dict_var_resized (v, new_val_count - old_val_count);
+  }
+
   dict_var_changed (v);
 }
 
index 602e59d20809b06b2e03510bba4092e3000d7eb2..23707386a7ea20278bcbd05c690b66d8f52fb42a 100644 (file)
@@ -1,3 +1,13 @@
+2007-07-18  John Darrington <john@darrington.wattle.id.au>
+
+       * psppire-case-file.c psppire-case-file.h psppire-data-store.c 
+       psppire-dict.c psppire-dict.h psppire-var-store.c : Added the
+       ability to resize string variables.  Fixed associated problems
+       inserting/deleting variables.   
+       
+       * helper.c helper.h (marshaller_VOID__INT_INT_INT): New marshaller
+       function.
+       
 2007-07-16  John Darrington <john@darrington.wattle.id.au>
 
        * data-editor.c: File Open dialog remembers directory.  Thanks to 
index 22072578d737fcc75333cbca70038adea29fa274..09711f1bd1a39f4d51aa3f764fbba901ec862a58 100644 (file)
@@ -20,6 +20,8 @@
 */
 #include <config.h>
 
+#include       <glib-object.h>
+
 #include <glib.h>
 #include "helper.h"
 #include "message-dialog.h"
@@ -208,3 +210,49 @@ execute_syntax (struct getl_interface *sss)
 }
 
 
+
+#ifdef G_ENABLE_DEBUG
+# define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#else
+# define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#endif
+
+
+/* VOID:INT,INT,INT */
+void
+marshaller_VOID__INT_INT_INT (GClosure     *closure,
+                        GValue       *return_value,
+                        guint         n_param_values,
+                        const GValue *param_values,
+                        gpointer      invocation_hint,
+                        gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__INT_INT_INT) (gpointer     data1,
+                                                 gint         arg_1,
+                                                 gint         arg_2,
+                                                 gint         arg_3,
+                                                 gpointer     data2);
+  register GMarshalFunc_VOID__INT_INT_INT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 4);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_int (param_values + 1),
+            g_marshal_value_peek_int (param_values + 2),
+            g_marshal_value_peek_int (param_values + 3),
+            data2);
+}
index 5a245361c3ba7500e9927e7fed322dc1b0be3b13..ddced00fc3d61c15e72d85d31d087dc56e1413e1 100644 (file)
@@ -61,5 +61,12 @@ gboolean execute_syntax (struct getl_interface *sss);
    glade_xml_new (relocate(PKGDATADIR "/" FILE), NULL, NULL)
 
 
+void marshaller_VOID__INT_INT_INT (GClosure     *closure,
+                                  GValue       *return_value,
+                                  guint         n_param_values,
+                                  const GValue *param_values,
+                                  gpointer      invocation_hint,
+                                  gpointer      marshal_data);
+
 
 #endif
index 7de97f5ca2e123df28423a2c5bdfe5915038e9a1..455ac2b755b7d412d89de82cfd6d1d775f7896d1 100644 (file)
@@ -341,25 +341,33 @@ psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
 
 
 /* Resize the cases in the casefile, by inserting N_VALUES into every
-   one of them. */
+   one of them at the position immediately preceeding WHERE.
+*/
 gboolean
 psppire_case_file_insert_values (PsppireCaseFile *cf,
-                                gint n_values, gint before)
+                                gint n_values, gint where)
 {
-  union value *values;
   g_return_val_if_fail (cf, FALSE);
   g_return_val_if_fail (cf->accessible, FALSE);
 
+  if ( n_values == 0 )
+    return FALSE;
+
+  g_assert (n_values > 0);
+
   if ( ! cf->datasheet )
     cf->datasheet = datasheet_create (NULL);
 
-  values = xcalloc (n_values, sizeof *values);
-  datasheet_insert_columns (cf->datasheet, values, n_values, before);
+  {
+    union value *values = xcalloc (n_values, sizeof *values);
+    datasheet_insert_columns (cf->datasheet, values, n_values, where);
   free (values);
+  }
 
   return TRUE;
 }
 
+
 /* Fills C with the CASENUMth case.
    Returns true on success, false otherwise.
  */
index 7ef3daa2a7b055f2e33e31fce6f70ec2367c51f0..1dc297ac5864e89320bd9e03f24c290f735c2418 100644 (file)
@@ -93,7 +93,7 @@ void psppire_case_file_clear (PsppireCaseFile *cf);
 gboolean psppire_case_file_delete_cases (PsppireCaseFile *cf, casenumber n_rows,
                                        casenumber first);
 
-gboolean psppire_case_file_insert_values (PsppireCaseFile *cf, gint n_values, gint before);
+gboolean psppire_case_file_insert_values (PsppireCaseFile *cf, gint n_values, gint where);
 
 struct case_ordering;
 
index 638661a58899701125eb67829d2509cdf328ae73..cc755761f60512b4e5bd60f0ec963f4ffde698c2 100644 (file)
@@ -282,30 +282,27 @@ changed_case_callback (GtkWidget *w, gint casenum, gpointer data)
 }
 
 
+/*
+   A callback which occurs after a variable has been deleted.
+ */
 static void
-delete_variables_callback (GObject *obj, gint var_num, gint n_vars, gpointer data)
+delete_variable_callback (GObject *obj, gint dict_index,
+                         gint case_index, gint val_cnt,
+                         gpointer data)
 {
-  PsppireDataStore *store ;
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
 
-  g_return_if_fail (data);
-
-  store  = PSPPIRE_DATA_STORE (data);
-
-  g_sheet_model_columns_deleted (G_SHEET_MODEL (store), var_num, n_vars);
+  g_sheet_model_columns_deleted (G_SHEET_MODEL (store), dict_index, 1);
 
   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
-                                  var_num, -1);
+                                  dict_index, -1);
 }
 
 
 static void
 variable_changed_callback (GObject *obj, gint var_num, gpointer data)
 {
-  PsppireDataStore *store;
-
-  g_return_if_fail (data);
-
-  store  = PSPPIRE_DATA_STORE (data);
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
 
   g_sheet_column_columns_changed (G_SHEET_COLUMN (store),
                                  var_num, 1);
@@ -353,13 +350,16 @@ static void
 dict_size_change_callback (GObject *obj,
                          gint posn, gint adjustment, gpointer data)
 {
-  PsppireDataStore *store ;
+  PsppireDataStore *store  = PSPPIRE_DATA_STORE (data);
 
-  g_return_if_fail (data);
+  const struct variable *v = psppire_dict_get_variable (store->dict, posn);
 
-  store  = PSPPIRE_DATA_STORE (data);
+  const gint new_val_width = value_cnt_from_width (var_get_width (v));
 
-  psppire_case_file_insert_values (store->case_file, adjustment, posn);
+  if ( adjustment > 0 )
+    psppire_case_file_insert_values (store->case_file, adjustment,
+                                    new_val_width - adjustment +
+                                    var_get_case_index(v));
 }
 
 
@@ -432,15 +432,14 @@ psppire_data_store_set_dictionary (PsppireDataStore *data_store, PsppireDict *di
                   G_CALLBACK (insert_variable_callback),
                   data_store);
 
-  g_signal_connect (dict, "variables-deleted",
-                  G_CALLBACK (delete_variables_callback),
+  g_signal_connect (dict, "variable-deleted",
+                  G_CALLBACK (delete_variable_callback),
                   data_store);
 
   g_signal_connect (dict, "variable-changed",
                   G_CALLBACK (variable_changed_callback),
                   data_store);
 
-
   g_signal_connect (dict, "dict-size-changed",
                    G_CALLBACK (dict_size_change_callback),
                    data_store);
index 3e37343b7d10b141bb5aebcf7a1d13b27897b466..31761136f8654601906ccd050aec107e8f59280f 100644 (file)
@@ -45,7 +45,7 @@ static GObjectClass     *parent_class = NULL;
 enum  {VARIABLE_CHANGED,
        VARIABLE_RESIZED,
        VARIABLE_INSERTED,
-       VARIABLES_DELETED,
+       VARIABLE_DELETED,
        WEIGHT_CHANGED,
        FILTER_CHANGED,
        SPLIT_CHANGED,
@@ -131,15 +131,16 @@ psppire_dict_class_init (PsppireDictClass *class)
                  G_TYPE_INT);
 
 
-  signals [VARIABLES_DELETED] =
-    g_signal_new ("variables_deleted",
+  signals [VARIABLE_DELETED] =
+    g_signal_new ("variable-deleted",
                  G_TYPE_FROM_CLASS (class),
                  G_SIGNAL_RUN_FIRST,
                  0,
                  NULL, NULL,
-                 gtkextra_VOID__INT_INT,
+                 marshaller_VOID__INT_INT_INT,
                  G_TYPE_NONE,
-                 2,
+                 3,
+                 G_TYPE_INT,
                  G_TYPE_INT,
                  G_TYPE_INT);
 
@@ -211,9 +212,11 @@ addcb (struct dictionary *d, int idx, void *pd)
 }
 
 static void
-delcb (struct dictionary *d, int idx, void *pd)
+delcb (struct dictionary *d, int dict_idx, int case_idx, int value_cnt,
+       void *pd)
 {
-  g_signal_emit (pd, signals [VARIABLES_DELETED], 0, idx, 1);
+  g_signal_emit (pd, signals [VARIABLE_DELETED], 0,
+                dict_idx, case_idx, value_cnt );
 }
 
 static void
@@ -222,6 +225,12 @@ mutcb (struct dictionary *d, int idx, void *pd)
   g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx);
 }
 
+static void
+resize_cb (struct dictionary *d, int idx, int delta, void *pd)
+{
+  g_signal_emit (pd, signals [VARIABLE_RESIZED], 0, idx, delta);
+}
+
 static void
 weight_changed_callback (struct dictionary *d, int idx, void *pd)
 {
@@ -246,6 +255,7 @@ static const struct dict_callbacks gui_callbacks =
     addcb,
     delcb,
     mutcb,
+    resize_cb,
     weight_changed_callback,
     filter_changed_callback,
     split_changed_callback
@@ -346,7 +356,6 @@ psppire_dict_delete_variables (PsppireDict *d, gint first, gint n)
       var = dict_get_var (d->dict, first);
       dict_delete_var (d->dict, var);
     }
-  dict_compact_values (d->dict);
 }
 
 
@@ -467,8 +476,6 @@ psppire_dict_resize_variable (PsppireDict *d, const struct variable *pv,
   if ( old_size == new_size )
     return ;
 
-  dict_compact_values (d->dict);
-
   fv = var_get_case_index (pv);
 
   g_signal_emit (d, signals [VARIABLE_RESIZED], 0,
@@ -764,3 +771,29 @@ psppire_dict_get_weight_variable (const PsppireDict *dict)
 {
   return dict_get_weight (dict->dict);
 }
+
+
+
+#if DEBUGGING
+void
+psppire_dict_dump (const PsppireDict *dict)
+{
+  gint i;
+  const struct dictionary *d = dict->dict;
+
+  int *map = dict_get_compacted_dict_index_to_case_index (d);
+
+  for (i = 0; i < dict_get_var_cnt (d); ++i)
+    {
+      const struct variable *v = psppire_dict_get_variable (dict, i);
+      int di = var_get_dict_index (v);
+      g_print ("\"%s\" idx=%d, fv=%d(%d), size=%d\n",
+              var_get_name(v),
+              di,
+              var_get_case_index(v),
+              map[di],
+              value_cnt_from_width(var_get_width(v)));
+
+    }
+}
+#endif
index 9314dbe4e2cdc16cc0d9bb6b3d3e8d22fc3b66d8..397097bf65159f023c20de5f5dc0d003d6345d70 100644 (file)
@@ -57,7 +57,6 @@ struct _PsppireDict
 struct _PsppireDictClass
 {
   GObjectClass parent_class;
-
 };
 
 
@@ -103,6 +102,9 @@ void psppire_dict_replace_dictionary (PsppireDict *, struct dictionary *);
 
 struct variable * psppire_dict_get_weight_variable (const PsppireDict *);
 
+#if DEBUGGING
+void psppire_dict_dump (const PsppireDict *);
+#endif
 
 G_END_DECLS
 
index 3ba2da2a24b6d13692b4aada461a118717d04e15..c296bfe2c7d438f7807931b02bfd402e9f3271b0 100644 (file)
@@ -271,11 +271,11 @@ var_change_callback (GtkWidget *w, gint n, gpointer data)
 
 
 static void
-var_delete_callback (GtkWidget *w, gint first, gint n, gpointer data)
+var_delete_callback (GtkWidget *w, gint dict_idx, gint case_idx, gint val_cnt, gpointer data)
 {
   GSheetModel *model = G_SHEET_MODEL (data);
 
-  g_sheet_model_rows_deleted (model, first, n);
+  g_sheet_model_rows_deleted (model, dict_idx, 1);
 }
 
 
@@ -308,7 +308,7 @@ psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *dict)
   g_signal_connect (dict, "variable-changed", G_CALLBACK (var_change_callback),
                   var_store);
 
-  g_signal_connect (dict, "variables-deleted", G_CALLBACK (var_delete_callback),
+  g_signal_connect (dict, "variable-deleted", G_CALLBACK (var_delete_callback),
                   var_store);
 
   g_signal_connect (dict, "variable-inserted", G_CALLBACK (var_insert_callback),