Ben for his comments.
+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.
{
size_t lcol;
+ assert ( start + cnt <= axis_get_size (ds->columns) );
+
/* Free up columns for reuse. */
for (lcol = start; lcol < start + cnt; lcol++)
{
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;
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)
{
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));
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
}
}
+
+/*
+ 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
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);
+ }
+}
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 *);
void dict_assign_short_names (struct dictionary *);
-/* Called only from variable.c */
-void dict_var_changed (const struct variable *v);
-
#endif /* dictionary.h */
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 */
#include "value-labels.h"
#include "vardict.h"
+#include <libpspp/misc.h>
#include <libpspp/alloc.h>
#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
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))
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);
}
+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
*/
#include <config.h>
+#include <glib-object.h>
+
#include <glib.h>
#include "helper.h"
#include "message-dialog.h"
}
+
+#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);
+}
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
/* 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.
*/
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;
}
+/*
+ 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);
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));
}
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);
enum {VARIABLE_CHANGED,
VARIABLE_RESIZED,
VARIABLE_INSERTED,
- VARIABLES_DELETED,
+ VARIABLE_DELETED,
WEIGHT_CHANGED,
FILTER_CHANGED,
SPLIT_CHANGED,
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);
}
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
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)
{
addcb,
delcb,
mutcb,
+ resize_cb,
weight_changed_callback,
filter_changed_callback,
split_changed_callback
var = dict_get_var (d->dict, first);
dict_delete_var (d->dict, var);
}
- dict_compact_values (d->dict);
}
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,
{
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
struct _PsppireDictClass
{
GObjectClass parent_class;
-
};
struct variable * psppire_dict_get_weight_variable (const PsppireDict *);
+#if DEBUGGING
+void psppire_dict_dump (const PsppireDict *);
+#endif
G_END_DECLS
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);
}
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),