5dccc849fc29d2247e8b7c4736214f9518c5a999
[pspp] / src / ui / gui / psppire-data-editor.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "ui/gui/psppire-data-editor.h"
20
21 #include <gtk/gtk.h>
22 #include <gtk-contrib/gtkxpaned.h>
23
24 #include "data/datasheet.h"
25 #include "data/value-labels.h"
26 #include "libpspp/range-set.h"
27 #include "libpspp/str.h"
28 #include "ui/gui/helper.h"
29 #include "ui/gui/pspp-sheet-selection.h"
30 #include "ui/gui/psppire-data-store.h"
31 #include "ui/gui/psppire-value-entry.h"
32 #include "ui/gui/psppire-var-sheet.h"
33 #include "ui/gui/psppire-conf.h"
34 #include "ui/gui/psppire-var-sheet-header.h"
35
36 #include "ui/gui/efficient-sheet/jmd-sheet.h"
37
38 #include <gettext.h>
39 #define _(msgid) gettext (msgid)
40
41
42 static GtkCellRenderer *
43 create_spin_renderer (GType type)
44 {
45   GtkCellRenderer *r = gtk_cell_renderer_spin_new ();
46       
47   GtkAdjustment *adj = gtk_adjustment_new (0,
48                                            0, G_MAXDOUBLE,
49                                            1, 1,
50                                            0);
51   g_object_set (r,
52                 "adjustment", adj,
53                 NULL);
54   
55   return r;
56 }
57
58 static GtkCellRenderer *
59 create_combo_renderer (GType type)
60 {
61   GtkListStore *list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
62   
63   GEnumClass *ec = g_type_class_ref (type);
64   
65   const GEnumValue *ev ;
66   for (ev = ec->values; ev->value_name; ++ev)
67     {
68       GtkTreeIter iter;
69
70       gtk_list_store_append (list_store, &iter);
71
72       gtk_list_store_set (list_store, &iter,
73                           0, ev->value,
74                           1, gettext (ev->value_nick),
75                           -1);
76     }
77
78   GtkCellRenderer *r = gtk_cell_renderer_combo_new ();
79
80   g_object_set (r,
81                 "model", list_store,
82                 "text-column", 1,
83                 "has-entry", TRUE,
84                 NULL);
85
86   return r;
87 }
88
89 GtkCellRenderer *xx ;
90 GtkCellRenderer *column_width_renderer ;
91 GtkCellRenderer *measure_renderer ;
92 GtkCellRenderer *alignment_renderer ;
93
94
95
96 static GtkCellRenderer *
97 select_renderer_func (gint col, gint row, GType type)
98 {
99   if (!xx)
100     xx = create_spin_renderer (type);
101
102   if (col == DICT_TVM_COL_ROLE && !column_width_renderer)
103     column_width_renderer = create_combo_renderer (type);
104
105   if (col == DICT_TVM_COL_MEASURE && !measure_renderer)
106     measure_renderer = create_combo_renderer (type);
107
108   if (col == DICT_TVM_COL_ALIGNMENT && !alignment_renderer)
109     alignment_renderer = create_combo_renderer (type);
110
111   switch  (col)
112     {
113     case DICT_TVM_COL_WIDTH:
114     case DICT_TVM_COL_DECIMAL:
115     case DICT_TVM_COL_COLUMNS:
116       return xx;
117       
118     case DICT_TVM_COL_ALIGNMENT:
119       return alignment_renderer;
120
121     case DICT_TVM_COL_MEASURE:
122       return measure_renderer;
123       
124     case DICT_TVM_COL_ROLE:
125       return column_width_renderer;
126     }
127   
128   return NULL;
129 }
130
131
132 static void psppire_data_editor_class_init          (PsppireDataEditorClass *klass);
133 static void psppire_data_editor_init                (PsppireDataEditor      *de);
134
135 static void disconnect_data_sheets (PsppireDataEditor *);
136 static void refresh_entry (PsppireDataEditor *);
137 static void psppire_data_editor_update_ui_manager (PsppireDataEditor *);
138
139 GType
140 psppire_data_editor_get_type (void)
141 {
142   static GType de_type = 0;
143
144   if (!de_type)
145     {
146       static const GTypeInfo de_info =
147       {
148         sizeof (PsppireDataEditorClass),
149         NULL, /* base_init */
150         NULL, /* base_finalize */
151         (GClassInitFunc) psppire_data_editor_class_init,
152         NULL, /* class_finalize */
153         NULL, /* class_data */
154         sizeof (PsppireDataEditor),
155         0,
156         (GInstanceInitFunc) psppire_data_editor_init,
157       };
158
159       de_type = g_type_register_static (GTK_TYPE_NOTEBOOK, "PsppireDataEditor",
160                                         &de_info, 0);
161     }
162
163   return de_type;
164 }
165
166 static GObjectClass * parent_class = NULL;
167
168 static void
169 psppire_data_editor_dispose (GObject *obj)
170 {
171   PsppireDataEditor *de = (PsppireDataEditor *) obj;
172
173   disconnect_data_sheets (de);
174
175   if (de->data_store)
176     {
177       g_object_unref (de->data_store);
178       de->data_store = NULL;
179     }
180
181   if (de->dict)
182     {
183       g_object_unref (de->dict);
184       de->dict = NULL;
185     }
186
187   if (de->font != NULL)
188     {
189       pango_font_description_free (de->font);
190       de->font = NULL;
191     }
192
193   if (de->ui_manager)
194     {
195       g_object_unref (de->ui_manager);
196       de->ui_manager = NULL;
197     }
198
199   /* Chain up to the parent class */
200   G_OBJECT_CLASS (parent_class)->dispose (obj);
201 }
202
203 enum
204   {
205     PROP_0,
206     PROP_DATA_STORE,
207     PROP_DICTIONARY,
208     PROP_VALUE_LABELS,
209     PROP_SPLIT_WINDOW,
210     PROP_UI_MANAGER
211   };
212
213 static void
214 psppire_data_editor_refresh_model (PsppireDataEditor *de)
215 {
216 }
217
218 static void
219 change_var_property (PsppireDict *dict, gint col, gint row, GValue *value)
220 {
221   /* Return the IDXth variable */
222   struct variable *var =  psppire_dict_get_variable (dict, row);
223
224   switch (col)
225     {
226     case DICT_TVM_COL_NAME:
227       dict_rename_var (dict->dict, var, g_value_get_string (value));
228       break;
229     case DICT_TVM_COL_LABEL:
230       var_set_label (var, g_value_get_string (value));
231       break;
232     case DICT_TVM_COL_COLUMNS:
233       var_set_display_width (var, g_value_get_int (value));
234       break;
235     default:
236       g_message ("Changing col %d of var sheet not yet supported", col);
237       break;
238     }
239 }
240
241 static void
242 change_data_value (PsppireDataStore *store, gint col, gint row, GValue *value)
243 {
244   const struct variable *var = psppire_dict_get_variable (store->dict, col);
245
246   union value v;
247   value_init (&v, var_get_width (var));
248   v.f = g_value_get_double (value);
249   
250   psppire_data_store_set_value (store, row, var, &v);
251
252   value_destroy (&v, var_get_width (var));
253 }
254
255 static void
256 psppire_data_editor_set_property (GObject         *object,
257                                   guint            prop_id,
258                                   const GValue    *value,
259                                   GParamSpec      *pspec)
260 {
261   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
262
263   switch (prop_id)
264     {
265     case PROP_SPLIT_WINDOW:
266       psppire_data_editor_split_window (de, g_value_get_boolean (value));
267       break;
268     case PROP_DATA_STORE:
269       if ( de->data_store)
270         {
271           g_signal_handlers_disconnect_by_func (de->data_store,
272                                                 G_CALLBACK (refresh_entry),
273                                                 de);
274           g_object_unref (de->data_store);
275         }
276
277       de->data_store = g_value_get_pointer (value);
278       g_object_ref (de->data_store);
279       g_print ("NEW STORE\n");
280
281       g_object_set (de->data_sheet, "data-model", de->data_store, NULL);
282       psppire_data_editor_refresh_model (de);
283
284       g_signal_connect_swapped (de->data_sheet, "value-changed",
285                                 G_CALLBACK (change_data_value), de->data_store);
286       
287       g_signal_connect_swapped (de->data_store, "case-changed",
288                                 G_CALLBACK (refresh_entry), de);
289
290       break;
291     case PROP_DICTIONARY:
292       if (de->dict)
293         g_object_unref (de->dict);
294       de->dict = g_value_get_pointer (value);
295       g_object_ref (de->dict);
296
297       g_object_set (de->data_sheet, "hmodel", de->dict, NULL);
298       g_object_set (de->var_sheet, "data-model", de->dict, NULL);
299       g_signal_connect_swapped (de->var_sheet, "value-changed",
300                                 G_CALLBACK (change_var_property), de->dict);
301
302       break;
303     case PROP_VALUE_LABELS:
304       break;
305     case PROP_UI_MANAGER:
306     default:
307       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308       break;
309     };
310 }
311
312 static void
313 psppire_data_editor_get_property (GObject         *object,
314                                   guint            prop_id,
315                                   GValue          *value,
316                                   GParamSpec      *pspec)
317 {
318   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
319
320   switch (prop_id)
321     {
322     case PROP_SPLIT_WINDOW:
323       g_value_set_boolean (value, de->split);
324       break;
325     case PROP_DATA_STORE:
326       g_value_set_pointer (value, de->data_store);
327       break;
328     case PROP_DICTIONARY:
329       g_value_set_pointer (value, de->dict);
330       break;
331     case PROP_VALUE_LABELS:
332       break;
333     case PROP_UI_MANAGER:
334       g_value_set_object (value, psppire_data_editor_get_ui_manager (de));
335       break;
336     default:
337       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338       break;
339     }
340 }
341
342 static void
343 psppire_data_editor_switch_page (GtkNotebook     *notebook,
344                                  GtkWidget *w,
345                                  guint            page_num)
346 {
347   GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, w, page_num);
348   psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (notebook));
349 }
350
351 static void
352 psppire_data_editor_set_focus_child (GtkContainer *container,
353                                      GtkWidget    *widget)
354 {
355   GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget);
356   psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container));
357 }
358
359 static void
360 psppire_data_editor_class_init (PsppireDataEditorClass *klass)
361 {
362   GParamSpec *data_store_spec ;
363   GParamSpec *dict_spec ;
364   GParamSpec *value_labels_spec;
365   GParamSpec *split_window_spec;
366   GParamSpec *ui_manager_spec;
367   GObjectClass *object_class = G_OBJECT_CLASS (klass);
368   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
369   GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
370
371   parent_class = g_type_class_peek_parent (klass);
372
373   object_class->dispose = psppire_data_editor_dispose;
374   object_class->set_property = psppire_data_editor_set_property;
375   object_class->get_property = psppire_data_editor_get_property;
376
377   container_class->set_focus_child = psppire_data_editor_set_focus_child;
378
379   notebook_class->switch_page = psppire_data_editor_switch_page;
380
381   data_store_spec =
382     g_param_spec_pointer ("data-store",
383                           "Data Store",
384                           "A pointer to the data store associated with this editor",
385                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
386
387   g_object_class_install_property (object_class,
388                                    PROP_DATA_STORE,
389                                    data_store_spec);
390
391   dict_spec =
392     g_param_spec_pointer ("dictionary",
393                           "Dictionary",
394                           "A pointer to the dictionary associated with this editor",
395                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
396
397   g_object_class_install_property (object_class,
398                                    PROP_DICTIONARY,
399                                    dict_spec);
400
401   value_labels_spec =
402     g_param_spec_boolean ("value-labels",
403                          "Value Labels",
404                          "Whether or not the data sheet should display labels instead of values",
405                           FALSE,
406                          G_PARAM_WRITABLE | G_PARAM_READABLE);
407
408   g_object_class_install_property (object_class,
409                                    PROP_VALUE_LABELS,
410                                    value_labels_spec);
411
412
413   split_window_spec =
414     g_param_spec_boolean ("split",
415                           "Split Window",
416                           "True iff the data sheet is split",
417                           FALSE,
418                           G_PARAM_READABLE | G_PARAM_WRITABLE);
419
420   g_object_class_install_property (object_class,
421                                    PROP_SPLIT_WINDOW,
422                                    split_window_spec);
423
424   ui_manager_spec =
425     g_param_spec_object ("ui-manager",
426                          "UI Manager",
427                          "UI manager for the active notebook tab.  The client should merge this UI manager with the active UI manager to obtain menu items and tool bar items specific to the active notebook tab.",
428                          GTK_TYPE_UI_MANAGER,
429                          G_PARAM_READABLE);
430   g_object_class_install_property (object_class,
431                                    PROP_UI_MANAGER,
432                                    ui_manager_spec);
433 }
434
435
436 static void
437 on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
438                                  PsppireDataEditor *de)
439 {
440   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
441                                  PSPPIRE_DATA_EDITOR_DATA_VIEW);
442
443   jmd_sheet_scroll_to (JMD_SHEET (de->data_sheet), dict_index, -1);
444 }
445
446 static void
447 on_data_sheet_var_double_clicked (JmdSheet *data_sheet, gint dict_index,
448                                  PsppireDataEditor *de)
449 {
450   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
451                                  PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
452
453   jmd_sheet_scroll_to (JMD_SHEET (de->var_sheet), -1, dict_index);
454 }
455
456
457 /* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
458    active cell or cells. */
459 static void
460 refresh_entry (PsppireDataEditor *de)
461 {
462   g_print ("%s\n", __FUNCTION__);
463 }
464
465 static void
466 on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
467 {
468 }
469
470
471 static void
472 disconnect_data_sheets (PsppireDataEditor *de)
473 {
474 }
475
476 /* Called when the active cell or the selection in the data sheet changes */
477 static void
478 on_data_selection_change (PsppireDataEditor *de, JmdRange *sel)
479 {
480   gchar *ref_cell_text = NULL;
481
482   gint n_cases = abs (sel->end_y - sel->start_y) + 1;
483   gint n_vars = abs (sel->end_x - sel->start_x) + 1;
484
485   if (n_cases == 1 && n_vars == 1)
486     {
487       /* A single cell is selected */
488       const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x);
489       
490       ref_cell_text = g_strdup_printf (_("%d : %s"),
491                                        sel->start_y + 1, var_get_name (var));
492     }
493   else
494     {
495       struct string s;
496
497       /* The glib string library does not understand the ' printf modifier
498          on all platforms, but the "struct string" library does (because
499          Gnulib fixes that problem), so use the latter.  */
500       ds_init_empty (&s);
501       ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
502                      n_cases);
503       ds_put_byte (&s, ' ');
504       ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
505       ds_put_byte (&s, ' ');
506       ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
507                                    n_vars),
508                      n_vars);
509       ref_cell_text = ds_steal_cstr (&s);
510     }
511   
512   gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
513                        ref_cell_text ? ref_cell_text : "");
514   
515   g_free (ref_cell_text);
516 }
517
518
519 static void set_font_recursively (GtkWidget *w, gpointer data);
520
521 static void
522 psppire_data_editor_init (PsppireDataEditor *de)
523 {
524   GtkWidget *hbox;
525   gchar *fontname = NULL;
526
527   de->font = NULL;
528   de->ui_manager = NULL;
529   de->old_vbox_widget = NULL;
530
531   g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
532
533   de->cell_ref_label = gtk_label_new ("");
534   gtk_label_set_width_chars (GTK_LABEL (de->cell_ref_label), 25);
535   gtk_widget_set_valign (de->cell_ref_label, GTK_ALIGN_CENTER);
536
537   de->datum_entry = psppire_value_entry_new ();
538   g_signal_connect (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))),
539                     "activate", G_CALLBACK (on_datum_entry_activate), de);
540
541   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
542   gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_label, FALSE, FALSE, 0);
543   gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
544
545   de->split = FALSE;
546   de->data_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
547   GtkWidget *data_button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet));
548   gtk_button_set_label (GTK_BUTTON (data_button), _("Case"));
549   de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
550   gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
551   gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0);
552
553
554   g_signal_connect_swapped (de->data_sheet, "selection-changed",
555                     G_CALLBACK (on_data_selection_change), de);
556   
557   gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
558                             gtk_label_new_with_mnemonic (_("Data View")));
559
560   gtk_widget_show_all (de->vbox);
561
562   de->var_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
563
564   PsppireVarSheetHeader *vsh = g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL);
565   
566   g_object_set (de->var_sheet,
567                 "hmodel", vsh,
568                 "select-renderer-func", select_renderer_func,
569                 NULL);
570
571   
572   GtkWidget *var_button = jmd_sheet_get_button (JMD_SHEET (de->var_sheet));
573   gtk_button_set_label (GTK_BUTTON (var_button), _("Variable"));
574   
575   gtk_notebook_append_page (GTK_NOTEBOOK (de), de->var_sheet,
576                             gtk_label_new_with_mnemonic (_("Variable View")));
577
578   gtk_widget_show_all (de->var_sheet);
579   
580   g_signal_connect (de->var_sheet, "row-header-double-clicked",
581                     G_CALLBACK (on_var_sheet_var_double_clicked), de);
582
583   g_signal_connect (de->data_sheet, "column-header-double-clicked",
584                     G_CALLBACK (on_data_sheet_var_double_clicked), de);
585
586   g_object_set (de, "can-focus", FALSE, NULL);
587
588   if (psppire_conf_get_string (psppire_conf_new (),
589                            "Data Editor", "font",
590                                 &fontname) )
591     {
592       de->font = pango_font_description_from_string (fontname);
593       g_free (fontname);
594       set_font_recursively (GTK_WIDGET (de), de->font);
595     }
596
597   psppire_data_editor_update_ui_manager (de);
598 }
599
600 GtkWidget*
601 psppire_data_editor_new (PsppireDict *dict,
602                          PsppireDataStore *data_store)
603 {
604   return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
605                         "dictionary",  dict,
606                         "data-store",  data_store,
607                         NULL);
608 }
609 \f
610 /* Turns the visible grid on or off, according to GRID_VISIBLE, for DE's data
611    sheet(s) and variable sheet. */
612 void
613 psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
614 {
615   GtkTreeViewGridLines grid;
616
617   grid = (grid_visible
618           ? GTK_TREE_VIEW_GRID_LINES_BOTH
619           : GTK_TREE_VIEW_GRID_LINES_NONE);
620
621   pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
622 }
623
624
625 static void
626 set_font_recursively (GtkWidget *w, gpointer data)
627 {
628   PangoFontDescription *font_desc = data;
629
630   gtk_widget_override_font (w, font_desc);
631
632   if ( GTK_IS_CONTAINER (w))
633     gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc);
634 }
635
636 /* Sets FONT_DESC as the font used by the data sheet(s) and variable sheet. */
637 void
638 psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
639 {
640   gchar *font_name;
641   set_font_recursively (GTK_WIDGET (de), font_desc);
642
643   if (de->font)
644     pango_font_description_free (de->font);
645   de->font = pango_font_description_copy (font_desc);
646   font_name = pango_font_description_to_string (de->font);
647
648   psppire_conf_set_string (psppire_conf_new (),
649                            "Data Editor", "font",
650                            font_name);
651
652 }
653
654 /* If SPLIT is TRUE, splits DE's data sheet into four panes.
655    If SPLIT is FALSE, un-splits it into a single pane. */
656 void
657 psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
658 {
659   if (split == de->split)
660     return;
661
662   disconnect_data_sheets (de);
663
664   psppire_data_editor_refresh_model (de);
665
666   gtk_widget_show_all (de->vbox);
667
668   if (de->font)
669     set_font_recursively (GTK_WIDGET (de), de->font);
670
671   de->split = split;
672   g_object_notify (G_OBJECT (de), "split");
673   psppire_data_editor_update_ui_manager (de);
674 }
675
676 /* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
677    visible and selected in the active view in DE. */
678 void
679 psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
680 {
681 }
682
683
684 /* Returns the UI manager that should be merged into DE's toplevel widget's UI
685    manager to display menu items and toolbar items specific to DE's current
686    page and data sheet.
687
688    DE's toplevel widget can watch for changes by connecting to DE's
689    notify::ui-manager signal. */
690 GtkUIManager *
691 psppire_data_editor_get_ui_manager (PsppireDataEditor *de)
692 {
693   psppire_data_editor_update_ui_manager (de);
694   return de->ui_manager;
695 }
696
697 static void
698 psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
699 {
700   GtkUIManager *ui_manager;
701
702   ui_manager = NULL;
703
704   switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
705     {
706     case PSPPIRE_DATA_EDITOR_DATA_VIEW:
707       break;
708
709     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
710       break;
711
712     default:
713       /* This happens transiently in psppire_data_editor_init(). */
714       break;
715     }
716
717   if (ui_manager != de->ui_manager)
718     {
719       if (de->ui_manager)
720         g_object_unref (de->ui_manager);
721       if (ui_manager)
722         g_object_ref (ui_manager);
723       de->ui_manager = ui_manager;
724
725       g_object_notify (G_OBJECT (de), "ui-manager");
726     }
727 }