gtk_sheet_draw_border (sheet, sheet->range);
}
--static void gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
-- GtkJustification justification,
-- const gchar *text);
--
--
static inline gint
safe_strcmp (const gchar *s1, const gchar *s2)
{
if ( !s1 && !s2) return 0;
-- if ( !s1) return - 1;
++ if ( !s1) return -1;
if ( !s2) return +1;
return strcmp (s1, s2);
}
old_text = g_sheet_model_get_string (model, row, col);
++ if (0 != safe_strcmp (old_text, text))
++ g_sheet_model_set_string (model, text, row, col);
++
if ( g_sheet_model_free_strings (model))
g_free (old_text);
}
text = gtk_entry_get_text (GTK_ENTRY (gtk_sheet_get_entry (sheet)));
++
++
if (text && strlen (text) > 0)
{
gtk_sheet_get_attributes (sheet, row, col, &attributes);
if (!sheet->column_titles_visible) return;
- if (column < min_visible_column (sheet)) return;
- if (column > max_visible_column (sheet)) return;
+ g_return_if_fail (first >= min_visible_column (sheet));
+ g_return_if_fail (last <= max_visible_column (sheet));
- button = g_sheet_model_get_column_button (sheet->model, column);
- allocation.y = 0;
- allocation.x = psppire_axis_pixel_start (sheet->haxis, column) + CELL_SPACING;
- allocation.x -= sheet->hadjustment->value;
+ region =
+ gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->column_title_window));
- allocation.height = sheet->column_title_area.height;
- allocation.width = psppire_axis_unit_size (sheet->haxis, column);
- is_sensitive = g_sheet_model_get_column_sensitivity (sheet->model, column);
+ gdk_window_begin_paint_region (sheet->column_title_window, region);
- gtk_sheet_button_draw (sheet, sheet->column_title_window,
- button, is_sensitive, allocation);
+ for (col = first ; col <= last ; ++col)
+ {
+ GdkRectangle allocation;
+ gboolean is_sensitive = FALSE;
+
+ GtkSheetButton *
- button = g_sheet_column_get_button (sheet->column_geometry, col);
++ button = g_sheet_model_get_column_button (sheet->model, col);
+ allocation.y = 0;
- allocation.x =
- g_sheet_column_start_pixel (sheet->column_geometry, col)
++ allocation.x = psppire_axis_pixel_start (sheet->haxis, col)
+ + CELL_SPACING;
+ allocation.x -= sheet->hadjustment->value;
+
+ allocation.height = sheet->column_title_area.height;
- allocation.width =
- g_sheet_column_get_width (sheet->column_geometry, col);
- is_sensitive =
- g_sheet_column_get_sensitivity (sheet->column_geometry, col);
++ allocation.width = psppire_axis_unit_size (sheet->haxis, col);
++ is_sensitive = g_sheet_model_get_column_sensitivity (sheet->model, col);
+
+ draw_button (sheet, sheet->column_title_window,
+ button, is_sensitive, allocation);
+ }
+
+ gdk_window_end_paint (sheet->column_title_window);
}
--- /dev/null
- tower_init (&axis->tower);
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2008 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libpspp/tower.h>
++#include <libpspp/pool.h>
+#include "psppire-axis.h"
+#include <gtk/gtk.h>
+
+
+/* --- prototypes --- */
+static void psppire_axis_class_init (PsppireAxisClass *class);
+static void psppire_axis_init (PsppireAxis *axis);
+static void psppire_axis_finalize (GObject *object);
+
+
+/* --- variables --- */
+static GObjectClass *parent_class = NULL;
+
+/* --- functions --- */
+/**
+ * psppire_axis_get_type:
+ * @returns: the type ID for accelerator groups.
+ */
+GType
+psppire_axis_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type)
+ {
+ static const GTypeInfo object_info = {
+ sizeof (PsppireAxisClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) psppire_axis_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PsppireAxis),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) psppire_axis_init,
+ };
+
+ object_type = g_type_register_static (G_TYPE_OBJECT,
+ "PsppireAxis",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+
+static void
+psppire_axis_class_init (PsppireAxisClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = psppire_axis_finalize;
+}
+
+static void
+psppire_axis_init (PsppireAxis *axis)
+{
- psppire_axis_new (gint w)
++ axis->pool = NULL;
++ psppire_axis_clear (axis);
+}
+
+
+static void
+psppire_axis_finalize (GObject *object)
+{
++ PsppireAxis *a = PSPPIRE_AXIS (object);
++ pool_destroy (a->pool);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/**
+ * psppire_axis_new:
+ * @returns: a new #PsppireAxis object
+ *
+ * Creates a new #PsppireAxis.
+ */
+PsppireAxis*
- PsppireAxis *new_axis = g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
-
- new_axis->width = w;
-
- return new_axis;
++psppire_axis_new (void)
+{
- if ( a->width == -1)
- {
- const struct tower_node *node;
- if (unit >= tower_count (&a->tower))
- return 0;
++ return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
+}
+
+
+gint
+psppire_axis_unit_size (PsppireAxis *a, gint unit)
+{
- node = tower_get (&a->tower, unit);
-
- return tower_node_get_size (node);
- }
++ const struct tower_node *node;
++ if (unit >= tower_count (&a->tower))
++ return 0;
+
- return a->width;
++ node = tower_get (&a->tower, unit);
+
- if (a->width == -1)
- return tower_count (&a->tower);
-
- return 600;
++ return tower_node_get_size (node);
+}
+
+gint
+psppire_axis_unit_count (PsppireAxis *a)
+{
- if ( a->width == -1 )
- {
- const struct tower_node *node;
++ return tower_count (&a->tower);
+}
+
+glong
+psppire_axis_pixel_start (PsppireAxis *a, gint unit)
+{
- if ( unit >= tower_count (&a->tower))
- return tower_height (&a->tower);
++ const struct tower_node *node;
+
- node = tower_get (&a->tower, unit);
-
- return tower_node_get_level (node);
- }
++ if ( unit >= tower_count (&a->tower))
++ return tower_height (&a->tower);
+
- return a->width * unit;
++ node = tower_get (&a->tower, unit);
+
- if (a->width == -1)
- {
- const struct tower_node *node;
- unsigned long int node_start;
++ return tower_node_get_level (node);
+}
+
+gint
+psppire_axis_get_unit_at_pixel (PsppireAxis *a, glong pixel)
+{
- if (pixel >= tower_height (&a->tower))
- return tower_count (&a->tower);
++ const struct tower_node *node;
++ unsigned long int node_start;
+
- node = tower_lookup (&a->tower, pixel, &node_start);
++ if (pixel >= tower_height (&a->tower))
++ return tower_count (&a->tower);
+
- return tower_node_get_index (node);
- }
++ node = tower_lookup (&a->tower, pixel, &node_start);
+
- return pixel / a->width;
++ return tower_node_get_index (node);
++}
+
- psppire_axis_append (PsppireAxis *a, gint width)
++void
++psppire_axis_append (PsppireAxis *a, gint size)
++{
++ struct tower_node *new = pool_malloc (a->pool, sizeof *new);
++
++ tower_insert (&a->tower, size, new, NULL);
+}
+
++
++
++/* Insert a new unit of size SIZE before position POSN */
+void
- struct tower_node *new = g_slice_alloc0 (sizeof *new);
- tower_insert (&a->tower, width, new, NULL);
++psppire_axis_insert (PsppireAxis *a, gint size, gint posn)
+{
++ struct tower_node *new = pool_malloc (a->pool, sizeof *new);
++
++ struct tower_node *before = tower_get (&a->tower, posn);
++
++ tower_insert (&a->tower, size, new, before);
++}
++
++
++void
++psppire_axis_remove (PsppireAxis *a, gint posn)
++{
++ struct tower_node *node = tower_get (&a->tower, posn);
++
++ tower_delete (&a->tower, node);
++
++ pool_free (a->pool, node);
+}
+
+
++void
++psppire_axis_resize_unit (PsppireAxis *a, gint size, gint posn)
++{
++ struct tower_node *node = tower_get (&a->tower, posn);
++
++ tower_resize (&a->tower, node, size);
++}
++
+
+
++void
++psppire_axis_clear (PsppireAxis *a)
++{
++ pool_destroy (a->pool);
++ a->pool = pool_create ();
++ tower_init (&a->tower);
++}
++
+
--- /dev/null
- gint width ;
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2008 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef PSPPIRE_AXIS_H__
+#define PSPPIRE_AXIS_H__
+
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include <libpspp/tower.h>
+
+G_BEGIN_DECLS
+
+
+/* --- type macros --- */
+#define G_TYPE_PSPPIRE_AXIS (psppire_axis_get_type ())
+#define PSPPIRE_AXIS(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_PSPPIRE_AXIS, PsppireAxis))
+#define PSPPIRE_AXIS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_PSPPIRE_AXIS, PsppireAxisClass))
+#define PSPPIRE_IS_AXIS(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_PSPPIRE_AXIS))
+#define PSPPIRE_IS_AXIS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_PSPPIRE_AXIS))
+#define PSPPIRE_AXIS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_PSPPIRE_AXIS, PsppireAxisClass))
+
+
+
+/* --- typedefs & structures --- */
+typedef struct _PsppireAxis PsppireAxis;
+typedef struct _PsppireAxisClass PsppireAxisClass;
+
++struct pool;
+
+struct _PsppireAxis
+{
+ GObject parent;
- PsppireAxis* psppire_axis_new (gint w);
+
+ struct tower tower;
++ struct pool *pool;
+};
+
+struct _PsppireAxisClass
+{
+ GObjectClass parent_class;
+
+};
+
+GType psppire_axis_get_type (void);
+
- void psppire_axis_append (PsppireAxis *a, gint width);
++PsppireAxis* psppire_axis_new (void);
+
+\f
+/* Interface between sheet and axis */
+
+gint psppire_axis_unit_size (PsppireAxis *a, gint unit);
+
+gint psppire_axis_unit_count (PsppireAxis *a);
+
+glong psppire_axis_pixel_start (PsppireAxis *a, gint unit);
+
+gint psppire_axis_get_unit_at_pixel (PsppireAxis *a, glong pixel);
+
+
+
+/* Interface between axis and model */
+
++void psppire_axis_clear (PsppireAxis *a);
++
++void psppire_axis_append (PsppireAxis *a, gint size);
++
++void psppire_axis_insert (PsppireAxis *a, gint size, gint posn);
++
++void psppire_axis_remove (PsppireAxis *a, gint posn);
++
++void psppire_axis_resize_unit (PsppireAxis *a, gint size, gint posn);
++
+
+G_END_DECLS
+
+#endif /* PSPPIRE_AXIS_H__ */
d->callbacks->var_resized (d, var_get_dict_index (v), delta, d->cb_data);
}
}
++
++/* Called from variable.c to notify the dictionary that the variable's display width
++ has changed */
++void
++dict_var_display_width_changed (const struct variable *v)
++{
++ if ( var_has_vardict (v))
++ {
++ const struct vardict_info *vdi = var_get_vardict (v);
++ struct dictionary *d;
++
++ d = vdi->dict;
++
++ if ( d->callbacks && d->callbacks->var_display_width_changed )
++ d->callbacks->var_display_width_changed (d, var_get_dict_index (v), d->cb_data);
++ }
++}
++
void (*weight_changed) (struct dictionary *, int, void *);
void (*filter_changed) (struct dictionary *, int, void *);
void (*split_changed) (struct dictionary *, void *);
++ void (*var_display_width_changed) (struct dictionary *, int, void *);
};
void dict_set_callbacks (struct dictionary *, const struct dict_callbacks *,
/* Called by variable.c, defined in dictionary.c. */
void dict_var_changed (const struct variable *v);
void dict_var_resized (const struct variable *v, int delta);
++void dict_var_display_width_changed (const struct variable *v);
#endif /* data/vardict.h */
/* Sets V's display width to DISPLAY_WIDTH. */
void
--var_set_display_width (struct variable *v, int display_width)
++var_set_display_width (struct variable *v, int new_width)
{
-- v->display_width = display_width;
++ int old_width = v->display_width;
++
++ v->display_width = new_width;
++
++ if ( old_width != new_width)
++ dict_var_display_width_changed (v);
++
dict_var_changed (v);
}
PROP_SPLIT_WINDOW
};
++
++#define WIDTH_OF_M 10
++
++static void
++new_variables_callback (PsppireDict *dict, gpointer data)
++{
++ gint v, i;
++ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
++
++ for (i = 0 ; i < 4 ; ++i)
++ {
++ PsppireAxis *haxis;
++ g_object_get (de->data_sheet[i], "horizontal-axis", &haxis, NULL);
++
++ psppire_axis_clear (haxis);
++
++ for (v = 0 ; v < psppire_dict_get_var_cnt (dict); ++v)
++ {
++ const struct variable *var = psppire_dict_get_variable (dict, v);
++
++ psppire_axis_append (haxis, 10 * var_get_display_width (var));
++ }
++ }
++}
++
++static void
++insert_variable_callback (PsppireDict *dict, gint x, gpointer data)
++{
++ gint i;
++ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
++
++ for (i = 0 ; i < 4 ; ++i)
++ {
++ const struct variable *var = psppire_dict_get_variable (dict, x);
++ PsppireAxis *haxis;
++ g_object_get (de->data_sheet[i], "horizontal-axis", &haxis, NULL);
++
++ psppire_axis_insert (haxis, WIDTH_OF_M * var_get_display_width (var), x);
++ }
++}
++
++
++static void
++delete_variable_callback (PsppireDict *dict, gint posn, gint x UNUSED, gint y UNUSED, gpointer data)
++{
++ gint i;
++ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
++
++ for (i = 0 ; i < 4 ; ++i)
++ {
++ PsppireAxis *haxis;
++ g_object_get (de->data_sheet[i], "horizontal-axis", &haxis, NULL);
++
++ psppire_axis_remove (haxis, posn);
++ }
++}
++
++
++static void
++rewidth_variable_callback (PsppireDict *dict, gint posn, gpointer data)
++{
++ gint i;
++ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (data);
++
++ for (i = 0 ; i < 4 ; ++i)
++ {
++ const struct variable *var = psppire_dict_get_variable (dict, posn);
++ PsppireAxis *haxis;
++ g_object_get (de->data_sheet[i], "horizontal-axis", &haxis, NULL);
++
++ psppire_axis_resize_unit (haxis, WIDTH_OF_M * var_get_display_width (var), posn);
++ }
++}
++
++
static void
psppire_data_editor_set_property (GObject *object,
guint prop_id,
for (i = 0 ; i < 4 ; ++i )
g_object_set (de->data_sheet[i],
"row-geometry", de->data_store,
- "column-geometry", de->data_store,
"model", de->data_store,
NULL);
++
++ g_signal_connect (de->data_store->dict, "backend-changed", G_CALLBACK (new_variables_callback), de);
++ g_signal_connect (de->data_store->dict, "variable-inserted", G_CALLBACK (insert_variable_callback), de);
++ g_signal_connect (de->data_store->dict, "variable-deleted", G_CALLBACK (delete_variable_callback), de);
++ // g_signal_connect (de->data_store->dict, "variable-changed", G_CALLBACK (alter_variable_callback), de);
++ g_signal_connect (de->data_store->dict, "variable-display-width-changed", G_CALLBACK (rewidth_variable_callback), de);
break;
case PROP_VAR_STORE:
if ( de->var_store) g_object_unref (de->var_store);
init_sheet (PsppireDataEditor *de, int i,
GtkAdjustment *hadj, GtkAdjustment *vadj)
{
- PsppireAxis *haxis = psppire_axis_new (100);
++ PsppireAxis *haxis = psppire_axis_new ();
de->sheet_bin[i] = gtk_scrolled_window_new (hadj, vadj);
de->data_sheet[i] = gtk_sheet_new (NULL, NULL, NULL);
psppire_data_editor_new (PsppireVarStore *var_store,
PsppireDataStore *data_store)
{
-- GtkWidget *widget;
--
-- widget = g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
-- "var-store", var_store,
-- "data-store", data_store,
-- NULL);
--
--
--
-- return widget;
++ return g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
++ "var-store", var_store,
++ "data-store", data_store,
++ NULL);
}
#include "helper.h"
#include "message-dialog.h"
--/* --- prototypes --- */
--static void psppire_dict_class_init (PsppireDictClass *class);
--static void psppire_dict_init (PsppireDict *dict);
--static void psppire_dict_finalize (GObject *object);
--
--static void dictionary_tree_model_init (GtkTreeModelIface *iface);
--
--
--/* --- variables --- */
--static GObjectClass *parent_class = NULL;
enum {
BACKEND_CHANGED,
VARIABLE_RESIZED,
VARIABLE_INSERTED,
VARIABLE_DELETED,
++ VARIABLE_DISPLAY_WIDTH_CHANGED,
WEIGHT_CHANGED,
FILTER_CHANGED,
n_SIGNALS
};
++
++/* --- prototypes --- */
++static void psppire_dict_class_init (PsppireDictClass *class);
++static void psppire_dict_init (PsppireDict *dict);
++static void psppire_dict_finalize (GObject *object);
++
++static void dictionary_tree_model_init (GtkTreeModelIface *iface);
++
++
++/* --- variables --- */
++static GObjectClass *parent_class = NULL;
++
static guint signals [n_SIGNALS];
/* --- functions --- */
g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
&tree_model_info);
--
--
}
return object_type;
G_TYPE_INT,
G_TYPE_INT);
++ signals [VARIABLE_DISPLAY_WIDTH_CHANGED] =
++ g_signal_new ("variable-display-width-changed",
++ G_TYPE_FROM_CLASS (class),
++ G_SIGNAL_RUN_FIRST,
++ 0,
++ NULL, NULL,
++ g_cclosure_marshal_VOID__INT,
++ G_TYPE_NONE,
++ 1,
++ G_TYPE_INT);
++
signals [WEIGHT_CHANGED] =
g_signal_new ("weight-changed",
static void
addcb (struct dictionary *d, int idx, void *pd)
{
-- g_signal_emit (pd, signals [VARIABLE_INSERTED], 0, idx);
++ PsppireDict *dict = PSPPIRE_DICT (pd);
++
++ if ( ! dict->disable_insert_signal)
++ g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
}
static void
g_signal_emit (pd, signals [SPLIT_CHANGED], 0);
}
++static void
++variable_display_width_callback (struct dictionary *d, int idx, void *pd)
++{
++ g_signal_emit (pd, signals [VARIABLE_DISPLAY_WIDTH_CHANGED], 0, idx);
++}
++
++
static const struct dict_callbacks gui_callbacks =
{
resize_cb,
weight_changed_callback,
filter_changed_callback,
-- split_changed_callback
++ split_changed_callback,
++ variable_display_width_callback
};
static void
psppire_dict_init (PsppireDict *psppire_dict)
{
psppire_dict->stamp = g_random_int ();
++ psppire_dict->disable_insert_signal = FALSE;
}
/**
if ( ! name )
name = auto_generate_var_name (d);
++ d->disable_insert_signal = TRUE;
++
var = dict_create_var (d->dict, name, 0);
dict_reorder_var (d->dict, var, idx);
++
++ d->disable_insert_signal = FALSE;
++
++ g_signal_emit (d, signals[VARIABLE_INSERTED], 0, idx);
}
/* Delete N variables beginning at FIRST */
#define PSPPIRE_DICT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_PSPPIRE_DICT, PsppireDictClass))
--
/* --- typedefs & structures --- */
typedef struct _PsppireDict PsppireDict;
typedef struct _PsppireDictClass PsppireDictClass;
GObject parent;
struct dictionary *dict;
++ gboolean disable_insert_signal;
/* For GtkTreeModelIface */
gint stamp;
};
GtkWidget*
psppire_var_sheet_new (void)
{
- return GTK_WIDGET (g_object_new (psppire_var_sheet_get_type (), NULL));
+ gint i;
- PsppireAxis *a = psppire_axis_new (-1);
++ PsppireAxis *a = psppire_axis_new ();
+ GtkWidget *w = g_object_new (psppire_var_sheet_get_type (), NULL);
+
+ for (i = 0 ; i < 10 ; ++i)
+ psppire_axis_append (a, column_def[i].width);
+
+ g_object_set (w,
+ "horizontal-axis", a,
+ NULL);
+
+ return w;
}