Merge branch 'rewrite-sheet' of ssh://jmd@git.sv.gnu.org/srv/git/pspp into rewrite...
authorJohn Darrington <john@darrington.wattle.id.au>
Mon, 24 Nov 2008 13:16:02 +0000 (22:16 +0900)
committerJohn Darrington <john@darrington.wattle.id.au>
Mon, 24 Nov 2008 13:16:02 +0000 (22:16 +0900)
Conflicts:

lib/gtksheet/gtksheet.c

lib/gtksheet/gtksheet.c
lib/gtksheet/psppire-axis.c
lib/gtksheet/psppire-axis.h
src/data/dictionary.c
src/data/dictionary.h
src/data/vardict.h
src/data/variable.c
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dict.h
src/ui/gui/psppire-var-sheet.c

index 31f242d28f1283648c517f7d122a2a1bd53a3751..8b25902c3b1cc2421c2e5e101b9dbeb77bc7aff8 100644 (file)
@@ -87,9 +87,9 @@ enum
 #define DEFAULT_ROW_HEIGHT 25
 
 static void gtk_sheet_update_primary_selection (GtkSheet *sheet);
-static void gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column);
+static void draw_column_title_buttons_range (GtkSheet *sheet, gint first, gint n);
+static void draw_row_title_buttons_range (GtkSheet *sheet, gint first, gint n);
 
-static void gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row);
 
 static void gtk_sheet_set_row_height (GtkSheet *sheet,
                                      gint row,
@@ -113,22 +113,6 @@ dispose_string (const GtkSheet *sheet, gchar *text)
     g_free (text);
 }
 
-static
-guint STRING_WIDTH (GtkWidget *widget,
-                   const PangoFontDescription *font, const gchar *text)
-{
-  PangoRectangle rect;
-  PangoLayout *layout;
-
-  layout = gtk_widget_create_pango_layout (widget, text);
-  pango_layout_set_font_description (layout, font);
-
-  pango_layout_get_extents (layout, NULL, &rect);
-
-  g_object_unref (layout);
-  return PANGO_PIXELS (rect.width);
-}
-
 /* Return the row containing pixel Y */
 static gint
 yyy_row_ypixel_to_row (const GtkSheet *sheet, gint y)
@@ -691,9 +675,6 @@ gtk_sheet_cell_get_type (void)
 }
 \f
 
-static void column_titles_changed (GtkWidget *w, gint first, gint n_columns,
-                                  gpointer data);
-
 /* Properties */
 enum
   {
@@ -1133,7 +1114,6 @@ columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
                                   gint n_columns,
                                   gpointer data)
 {
-  gint i;
   GtkSheet *sheet = GTK_SHEET (data);
 
   GtkSheetRange range;
@@ -1153,8 +1133,8 @@ columns_inserted_deleted_callback (GSheetModel *model, gint first_column,
   if (sheet->active_cell.col >= model_columns)
     change_active_cell (sheet, sheet->active_cell.row, model_columns - 1);
 
-  for (i = first_column; i <= max_visible_column (sheet); i++)
-    gtk_sheet_column_title_button_draw (sheet, i);
+  draw_column_title_buttons_range (sheet,
+                                  first_column, max_visible_column (sheet));
 
   gtk_sheet_range_draw (sheet, &range);
 }
@@ -1165,7 +1145,6 @@ static void
 rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
                                gint n_rows, gpointer data)
 {
-  gint i;
   GtkSheet *sheet = GTK_SHEET (data);
 
   GtkSheetRange range;
@@ -1185,8 +1164,7 @@ rows_inserted_deleted_callback (GSheetModel *model, gint first_row,
   if (sheet->active_cell.row >= model_rows)
     change_active_cell (sheet, model_rows - 1, sheet->active_cell.col);
 
-  for (i = first_row; i <= max_visible_row (sheet); i++)
-    gtk_sheet_row_title_button_draw (sheet, i);
+  draw_row_title_buttons_range (sheet, first_row, max_visible_row (sheet));
 
   gtk_sheet_range_draw (sheet, &range);
 }
@@ -1220,16 +1198,14 @@ range_update_callback (GSheetModel *m, gint row0, gint col0,
 
   if ( ( row0 < 0 && col0 < 0 ) || ( rowi < 0 && coli < 0 ) )
     {
-      gint i;
       gtk_sheet_range_draw (sheet, NULL);
       adjust_scrollbars (sheet);
 
-      for (i = min_visible_row (sheet); i <= max_visible_row (sheet); i++)
-       gtk_sheet_row_title_button_draw (sheet, i);
+      draw_row_title_buttons_range (sheet, min_visible_row (sheet),
+                                      max_visible_row (sheet));
 
-      for (i = min_visible_column (sheet);
-          i <= max_visible_column (sheet); i++)
-       gtk_sheet_column_title_button_draw (sheet, i);
+      draw_column_title_buttons_range (sheet, min_visible_column (sheet),
+                                      max_visible_column (sheet));
 
       return;
     }
@@ -1309,27 +1285,6 @@ gtk_sheet_set_model (GtkSheet *sheet, GSheetModel *model)
 }
 
 
-/* Call back for when the column titles have changed.
-   FIRST is the first column changed.
-   N_COLUMNS is the number of columns which have changed, or -1, which
-   indicates that the column has changed to its right-most extremity
-*/
-static void
-column_titles_changed (GtkWidget *w, gint first, gint n_columns, gpointer data)
-{
-  GtkSheet *sheet = GTK_SHEET (data);
-  gboolean extremity = FALSE;
-
-  if ( n_columns == -1 )
-    {
-      extremity = TRUE;
-      n_columns = psppire_axis_unit_count (sheet->haxis) - 1 ;
-    }
-
-  if ( extremity)
-    gtk_sheet_column_title_button_draw (sheet, -1);
-}
-
 void
 gtk_sheet_change_entry (GtkSheet *sheet, GtkType entry_type)
 {
@@ -1391,42 +1346,6 @@ gtk_sheet_set_column_width (GtkSheet *sheet,
                            guint width);
 
 
-static void
-gtk_sheet_autoresize_column (GtkSheet *sheet, gint column)
-{
-  gint text_width = 0;
-  gint row;
-
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (GTK_IS_SHEET (sheet));
-  if (column >= psppire_axis_unit_count (sheet->haxis) || column < 0) return;
-
-  for (row = 0; row < g_sheet_row_get_row_count (sheet->row_geometry); row++)
-    {
-      gchar *text = gtk_sheet_cell_get_text (sheet, row, column);
-      if (text && strlen (text) > 0)
-       {
-         GtkSheetCellAttr attributes;
-
-         gtk_sheet_get_attributes (sheet, row, column, &attributes);
-         if (attributes.is_visible)
-           {
-             gint width = STRING_WIDTH (GTK_WIDGET (sheet),
-                                        attributes.font_desc,
-                                        text)
-               + 2 * COLUMN_TITLES_HEIGHT + attributes.border.width;
-             text_width = MAX (text_width, width);
-           }
-       }
-      dispose_string (sheet, text);
-    }
-
-  if (text_width > psppire_axis_unit_size (sheet->haxis, column) )
-    {
-      gtk_sheet_set_column_width (sheet, column, text_width);
-    }
-}
-
 void
 gtk_sheet_show_column_titles (GtkSheet *sheet)
 {
@@ -2338,16 +2257,11 @@ gtk_sheet_range_draw_selection (GtkSheet *sheet, GtkSheetRange range)
   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);
 }
@@ -2373,6 +2287,9 @@ gtk_sheet_set_cell (GtkSheet *sheet, gint row, gint col,
 
   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);
 }
@@ -2625,6 +2542,8 @@ gtk_sheet_entry_changed (GtkWidget *widget, gpointer data)
 
   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);
@@ -2778,7 +2697,6 @@ gtk_sheet_show_active_cell (GtkSheet *sheet)
   gtk_widget_grab_focus (GTK_WIDGET (sheet_entry));
 
   dispose_string (sheet, text);
-
 }
 
 static void
@@ -3197,19 +3115,17 @@ gtk_sheet_expose (GtkWidget *widget,
   if (event->window == sheet->row_title_window &&
       sheet->row_titles_visible)
     {
-      gint i;
-      for (i = min_visible_row (sheet); i <= max_visible_row (sheet); i++)
-       gtk_sheet_row_title_button_draw (sheet, i);
+      draw_row_title_buttons_range (sheet,
+                                   min_visible_row (sheet),
+                                   max_visible_row (sheet));
     }
 
   if (event->window == sheet->column_title_window &&
       sheet->column_titles_visible)
     {
-      gint i;
-      for (i = min_visible_column (sheet);
-          i <= max_visible_column (sheet);
-          ++i)
-       gtk_sheet_column_title_button_draw (sheet, i);
+      draw_column_title_buttons_range (sheet,
+                                      min_visible_column (sheet),
+                                      max_visible_column (sheet));
     }
 
 
@@ -3344,12 +3260,6 @@ gtk_sheet_button_press (GtkWidget *widget,
       if (on_column_boundary (sheet, sheet->x_drag, &sheet->drag_cell.col))
        {
          guint req;
-         if (event->type == GDK_2BUTTON_PRESS)
-           {
-             gtk_sheet_autoresize_column (sheet, sheet->drag_cell.col);
-             GTK_SHEET_UNSET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
-             return TRUE;
-           }
          gtk_sheet_column_size_request (sheet, sheet->drag_cell.col, &req);
          GTK_SHEET_SET_FLAGS (sheet, GTK_SHEET_IN_XDRAG);
          gdk_pointer_grab (sheet->column_title_window, FALSE,
@@ -4503,9 +4413,6 @@ gtk_sheet_size_allocate (GtkWidget *widget,
                            sheet->column_title_area.height);
 
 
-  /* column button allocation */
-  draw_column_title_buttons (sheet);
-
   /* position the window which holds the row title buttons */
   sheet->row_title_area.x = 0;
   sheet->row_title_area.y = 0;
@@ -4525,10 +4432,6 @@ gtk_sheet_size_allocate (GtkWidget *widget,
                            sheet->row_title_area.height);
 
 
-  /* row button allocation */
-  draw_row_title_buttons (sheet);
-  draw_column_title_buttons (sheet);
-
   /* set the scrollbars adjustments */
   adjust_scrollbars (sheet);
 }
@@ -4536,7 +4439,6 @@ gtk_sheet_size_allocate (GtkWidget *widget,
 static void
 draw_column_title_buttons (GtkSheet *sheet)
 {
-  gint i;
   gint x, width;
 
   if (!sheet->column_titles_visible) return;
@@ -4573,14 +4475,13 @@ draw_column_title_buttons (GtkSheet *sheet)
 
   size_allocate_global_button (sheet);
 
-  for (i = min_visible_column (sheet); i <= max_visible_column (sheet); i++)
-    gtk_sheet_column_title_button_draw (sheet, i);
+  draw_column_title_buttons_range (sheet, min_visible_column (sheet), 
+                                  max_visible_column (sheet));
 }
 
 static void
 draw_row_title_buttons (GtkSheet *sheet)
 {
-  gint i;
   gint y = 0;
   gint height;
 
@@ -4616,12 +4517,9 @@ draw_row_title_buttons (GtkSheet *sheet)
 
   size_allocate_global_button (sheet);
 
-  for (i = min_visible_row (sheet); i <= max_visible_row (sheet); i++)
-    {
-      if ( i >= g_sheet_row_get_row_count (sheet->row_geometry))
-       break;
-      gtk_sheet_row_title_button_draw (sheet, i);
-    }
+
+  draw_row_title_buttons_range (sheet, min_visible_row (sheet),
+                               max_visible_row (sheet));
 }
 
 
@@ -4777,7 +4675,7 @@ gtk_sheet_get_entry_widget (GtkSheet *sheet)
 
 
 static void
-gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
+draw_button (GtkSheet *sheet, GdkWindow *window,
                       GtkSheetButton *button, gboolean is_sensitive,
                       GdkRectangle allocation)
 {
@@ -4788,8 +4686,6 @@ gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
   gboolean rtl ;
 
   gint state = 0;
-  gint len = 0;
-  gchar *line = 0;
 
   g_return_if_fail (sheet != NULL);
   g_return_if_fail (button != NULL);
@@ -4826,8 +4722,7 @@ gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
 
   if (button->label_visible)
     {
-
-      text_height = DEFAULT_ROW_HEIGHT - 
+      text_height = DEFAULT_ROW_HEIGHT -
        2 * COLUMN_TITLES_HEIGHT;
 
       gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
@@ -4837,68 +4732,46 @@ gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
 
       allocation.y += 2 * sheet->button->style->ythickness;
 
-
       if (button->label && strlen (button->label)>0)
        {
-         gchar *words = 0;
+         PangoRectangle rect;
+         gchar *line = button->label;
+
          PangoLayout *layout = NULL;
-         gint real_x = allocation.x, real_y = allocation.y;
+         gint real_x = allocation.x;
+         gint real_y = allocation.y;
 
-         words = button->label;
-         line = g_new (gchar, 1);
-         line[0]='\0';
+         layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
+         pango_layout_get_extents (layout, NULL, &rect);
 
-         while (words && *words != '\0')
+         text_width = PANGO_PIXELS (rect.width);
+         switch (button->justification)
            {
-             if (*words != '\n')
-               {
-                 len = strlen (line);
-                 line = g_realloc (line, len + 2);
-                 line[len]=*words;
-                 line[len + 1]='\0';
-               }
-             if (*words == '\n' || * (words + 1) == '\0')
-               {
-                 text_width = STRING_WIDTH (GTK_WIDGET (sheet), GTK_WIDGET (sheet)->style->font_desc, line);
-
-                 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), line);
-                 switch (button->justification)
-                   {
-                   case GTK_JUSTIFY_LEFT:
-                     real_x = allocation.x + COLUMN_TITLES_HEIGHT;
-                     align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-                     break;
-                   case GTK_JUSTIFY_RIGHT:
-                     real_x = allocation.x + allocation.width - text_width - COLUMN_TITLES_HEIGHT;
-                     align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
-                     break;
-                   case GTK_JUSTIFY_CENTER:
-                   default:
-                     real_x = allocation.x + (allocation.width - text_width)/2;
-                     align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-                     pango_layout_set_justify (layout, TRUE);
-                   }
-                 pango_layout_set_alignment (layout, align);
-                 gtk_paint_layout (GTK_WIDGET (sheet)->style,
-                                   window,
-                                   state,
-                                   FALSE,
-                                   &allocation,
-                                   GTK_WIDGET (sheet),
-                                   "label",
-                                   real_x, real_y,
-                                   layout);
-                 g_object_unref (layout);
-
-                 real_y += text_height + 2;
-
-                 g_free (line);
-                 line = g_new (gchar, 1);
-                 line[0]='\0';
-               }
-             words++;
+           case GTK_JUSTIFY_LEFT:
+             real_x = allocation.x + COLUMN_TITLES_HEIGHT;
+             align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
+             break;
+           case GTK_JUSTIFY_RIGHT:
+             real_x = allocation.x + allocation.width - text_width - COLUMN_TITLES_HEIGHT;
+             align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
+             break;
+           case GTK_JUSTIFY_CENTER:
+           default:
+             real_x = allocation.x + (allocation.width - text_width)/2;
+             align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
+             pango_layout_set_justify (layout, TRUE);
            }
-         g_free (line);
+         pango_layout_set_alignment (layout, align);
+         gtk_paint_layout (GTK_WIDGET (sheet)->style,
+                           window,
+                           state,
+                           FALSE,
+                           &allocation,
+                           GTK_WIDGET (sheet),
+                           "label",
+                           real_x, real_y,
+                           layout);
+         g_object_unref (layout);
        }
 
       gdk_gc_set_clip_rectangle (GTK_WIDGET (sheet)->style->fg_gc[button->state],
@@ -4910,60 +4783,90 @@ gtk_sheet_button_draw (GtkSheet *sheet, GdkWindow *window,
   gtk_sheet_button_free (button);
 }
 
+
+/* Draw the column title buttons FIRST through to LAST */
 static void
-gtk_sheet_column_title_button_draw (GtkSheet *sheet, gint column)
+draw_column_title_buttons_range (GtkSheet *sheet, gint first, gint last)
 {
-  GdkRectangle allocation;
-  GtkSheetButton *button = NULL;
-  gboolean is_sensitive = FALSE;
-
+  GdkRegion *region;
+  gint col;
   if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
 
   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);
+
+  for (col = first ; col <= last ; ++col)
+    {
+      GdkRectangle allocation;
+      gboolean is_sensitive = FALSE;
+
+      GtkSheetButton *
+       button = g_sheet_model_get_column_button (sheet->model, col);
+      allocation.y = 0;
+      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 = 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);
+    }
 
-  gtk_sheet_button_draw (sheet, sheet->column_title_window,
-                        button, is_sensitive, allocation);
+  gdk_window_end_paint (sheet->column_title_window);
 }
 
 
 static void
-gtk_sheet_row_title_button_draw (GtkSheet *sheet, gint row)
+draw_row_title_buttons_range (GtkSheet *sheet, gint first, gint last)
 {
-  GdkRectangle allocation;
-  GtkSheetButton *button = NULL;
-  gboolean is_sensitive = FALSE;
-
-
+  GdkRegion *region;
+  gint row;
   if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
 
   if (!sheet->row_titles_visible) return;
 
-  if (row < min_visible_row (sheet)) return;
-  if (row > max_visible_row (sheet)) return;
+  g_return_if_fail (first >= min_visible_row (sheet));
+  g_return_if_fail (last <= max_visible_row (sheet));
 
-  button = g_sheet_row_get_button (sheet->row_geometry, row);
-  allocation.x = 0;
-  allocation.y = g_sheet_row_start_pixel (sheet->row_geometry, row) + CELL_SPACING;
-  allocation.y -= sheet->vadjustment->value;
 
-  allocation.width = sheet->row_title_area.width;
-  allocation.height = g_sheet_row_get_height (sheet->row_geometry, row);
-  is_sensitive = g_sheet_row_get_sensitivity (sheet->row_geometry, row);
+  region =
+    gdk_drawable_get_visible_region (GDK_DRAWABLE (sheet->row_title_window));
+
+  gdk_window_begin_paint_region (sheet->row_title_window, region);
+
+
+  for (row = first; row <= last; ++row)
+    {
+      GdkRectangle allocation;
+
+      gboolean is_sensitive = FALSE;
+
+      GtkSheetButton *button =
+       g_sheet_row_get_button (sheet->row_geometry, row);
+      allocation.x = 0;
+      allocation.y = g_sheet_row_start_pixel (sheet->row_geometry, row)
+       + CELL_SPACING;
+      allocation.y -= sheet->vadjustment->value;
+
+      allocation.width = sheet->row_title_area.width;
+      allocation.height = g_sheet_row_get_height (sheet->row_geometry, row);
+      is_sensitive = g_sheet_row_get_sensitivity (sheet->row_geometry, row);
+
+      draw_button (sheet, sheet->row_title_window,
+                  button, is_sensitive, allocation);
+    }
 
-  gtk_sheet_button_draw (sheet, sheet->row_title_window,
-                        button, is_sensitive, allocation);
+  gdk_window_end_paint (sheet->row_title_window);
 }
 
 /* SCROLLBARS
index 2a69fbef07351a6d4ca7d24ed981a2c0a9ab142c..a3609afae6101fa925cb9705513dbd577c8763f4 100644 (file)
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 
 #include <libpspp/tower.h>
+#include <libpspp/pool.h>
 #include "psppire-axis.h"
 #include <gtk/gtk.h>
 
@@ -78,13 +79,16 @@ psppire_axis_class_init (PsppireAxisClass *class)
 static void
 psppire_axis_init (PsppireAxis *axis)
 {
-  tower_init (&axis->tower);
+  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);
 }
 
@@ -95,87 +99,106 @@ psppire_axis_finalize (GObject *object)
  * Creates a new #PsppireAxis.
  */
 PsppireAxis*
-psppire_axis_new (gint w)
+psppire_axis_new (void)
 {
-  PsppireAxis *new_axis = g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
-
-  new_axis->width = w;
-
-  return new_axis;
+  return g_object_new (G_TYPE_PSPPIRE_AXIS, NULL);
 }
 
 
 gint
 psppire_axis_unit_size (PsppireAxis *a, gint unit)
 {
-  if ( a->width == -1)
-    {
-      const struct tower_node *node;
-      if  (unit >= tower_count (&a->tower))
-       return 0;
+  const struct tower_node *node;
+  if  (unit >= tower_count (&a->tower))
+    return 0;
 
-      node = tower_get (&a->tower, unit);
-
-      return tower_node_get_size (node);
-    }
+  node = tower_get (&a->tower, unit);
 
-  return a->width;
+  return tower_node_get_size (node);
 }
 
 gint
 psppire_axis_unit_count (PsppireAxis *a)
 {
-  if (a->width == -1)
-    return tower_count (&a->tower);
-
-  return 600;
+  return tower_count (&a->tower);
 }
 
 glong
 psppire_axis_pixel_start (PsppireAxis *a, gint unit)
 {
-  if ( a->width == -1 )
-    {
-      const struct tower_node *node;
+  const struct tower_node *node;
 
-      if ( unit >= tower_count (&a->tower))
-       return tower_height (&a->tower);
+  if ( unit >= tower_count (&a->tower))
+    return tower_height (&a->tower);
 
-      node = tower_get (&a->tower, unit);
-
-      return  tower_node_get_level (node);
-    }
+  node = tower_get (&a->tower, unit);
 
-  return a->width * unit;
+  return  tower_node_get_level (node);
 }
 
 gint
 psppire_axis_get_unit_at_pixel (PsppireAxis *a, glong pixel)
 {
-  if (a->width == -1)
-    {
-      const struct tower_node *node;
-      unsigned long int node_start;
+  const struct tower_node *node;
+  unsigned long int node_start;
 
-      if (pixel >= tower_height (&a->tower))
-       return tower_count (&a->tower);
+  if (pixel >= tower_height (&a->tower))
+    return tower_count (&a->tower);
 
-      node = tower_lookup (&a->tower, pixel, &node_start);
+  node = tower_lookup (&a->tower, pixel, &node_start);
 
-      return tower_node_get_index (node);
-    }
+  return tower_node_get_index (node);
+}
 
-  return pixel / a->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
-psppire_axis_append (PsppireAxis *a, gint width)
+psppire_axis_insert (PsppireAxis *a, gint size, gint posn)
 {
-  struct tower_node *new = g_slice_alloc0 (sizeof *new);
-  tower_insert (&a->tower, width, new, NULL);
+  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);
+}
+
 
index 8c362d6e11036b31f784b1d21bda348b209edf03..72484773e895c88767b794887e065609440b46a6 100644 (file)
@@ -41,13 +41,14 @@ G_BEGIN_DECLS
 typedef struct _PsppireAxis       PsppireAxis;
 typedef struct _PsppireAxisClass PsppireAxisClass;
 
+struct pool;
 
 struct _PsppireAxis
 {
   GObject             parent;
-  gint width ;
 
   struct tower tower;
+  struct pool *pool;
 };
 
 struct _PsppireAxisClass
@@ -58,7 +59,7 @@ struct _PsppireAxisClass
 
 GType          psppire_axis_get_type (void);
 
-PsppireAxis*   psppire_axis_new (gint w);
+PsppireAxis*   psppire_axis_new (void);
 
 \f
 /* Interface between sheet and axis */
@@ -75,7 +76,16 @@ gint psppire_axis_get_unit_at_pixel (PsppireAxis *a, glong pixel);
 
 /* Interface between axis and model */
 
-void psppire_axis_append (PsppireAxis *a, gint width);
+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
 
index caf8e2fc3490cc81968197e732b74f45a5aa14f3..02c6aa76bc5c991a2bc077ed9bc91a3e60972eea 100644 (file)
@@ -1352,3 +1352,21 @@ dict_var_resized (const struct variable *v, int delta)
        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);
+    }
+}
+
index bb14f52ebef0fe7560ddab190693f75be8b6457f..682409e24216a11c7492cb39082b30d62f101f19 100644 (file)
@@ -157,6 +157,7 @@ struct dict_callbacks
   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 *,
index 35440a0de644af2fbeb3a407d7da837fe97aca1d..dfde1bffc0b3802d553c7717da47b82a4300908b 100644 (file)
@@ -41,5 +41,6 @@ void var_clear_vardict (struct variable *);
 /* 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 */
index d14237d925c3442e4baa8bbf9204a09044f41818..ccbe65dc0ed9757be75091637bb346b276182d84 100644 (file)
@@ -778,9 +778,15 @@ var_get_display_width (const struct variable *v)
 
 /* 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);
 }
 
index fe4fcb62a5ed8b81d5035e4326fe02f41a96f44a..2e1dee8954aa5a59dd7d3707d19c96fcecd04eb9 100644 (file)
@@ -198,6 +198,81 @@ enum
     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,
@@ -222,6 +297,12 @@ psppire_data_editor_set_property (GObject         *object,
                      "row-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);
@@ -611,7 +692,7 @@ static void
 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);
@@ -789,16 +870,10 @@ GtkWidget*
 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);
 }
 
 
index e6f1373a54d969ed76de022e0135924ace674c8c..8f7fed618fcedbfd8e8d4463eca07dff111ee2c5 100644 (file)
 #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,
@@ -48,6 +38,7 @@ enum  {
   VARIABLE_RESIZED,
   VARIABLE_INSERTED,
   VARIABLE_DELETED,
+  VARIABLE_DISPLAY_WIDTH_CHANGED,
 
   WEIGHT_CHANGED,
   FILTER_CHANGED,
@@ -55,6 +46,18 @@ enum  {
   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 --- */
@@ -93,8 +96,6 @@ psppire_dict_get_type (void)
 
       g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
                                   &tree_model_info);
-
-
     }
 
   return object_type;
@@ -172,6 +173,17 @@ psppire_dict_class_init (PsppireDictClass *class)
                  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",
@@ -223,7 +235,10 @@ psppire_dict_finalize (GObject *object)
 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
@@ -264,6 +279,13 @@ split_changed_callback (struct dictionary *d, void *pd)
   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 =
   {
@@ -273,13 +295,15 @@ 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;
 }
 
 /**
@@ -349,9 +373,15 @@ psppire_dict_insert_variable (PsppireDict *d, gint idx, const gchar *name)
   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 */
index 1bf8bd3523b849aac1c2918f2794895c088714af..534f0707ea22df8bc6084a1d8193c917d4ae0e0a 100644 (file)
@@ -38,7 +38,6 @@ G_BEGIN_DECLS
 #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;
@@ -50,6 +49,7 @@ struct _PsppireDict
   GObject             parent;
   struct dictionary *dict;
 
+  gboolean disable_insert_signal;
   /* For GtkTreeModelIface */
   gint stamp;
 };
index 5406949108968a467a6b1686b73d93eda5f07dc3..033652025a870812214b84dcf630702cb04942a2 100644 (file)
@@ -534,7 +534,7 @@ GtkWidget*
 psppire_var_sheet_new (void)
 {
   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)