Merge remote-tracking branch 'origin/master' into sheet
[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     case DICT_TVM_COL_MEASURE:
236       var_set_measure (var, g_value_get_enum (value));
237       break;
238     case DICT_TVM_COL_ALIGNMENT:
239       var_set_alignment (var, g_value_get_enum (value));
240       break;
241     case DICT_TVM_COL_ROLE:
242       var_set_role (var, g_value_get_enum (value));
243       break;
244     default:
245       g_message ("Changing col %d of var sheet not yet supported", col);
246       break;
247     }
248 }
249
250 static void
251 change_data_value (PsppireDataStore *store, gint col, gint row, GValue *value)
252 {
253   const struct variable *var = psppire_dict_get_variable (store->dict, col);
254
255   union value v;
256   value_init (&v, var_get_width (var));
257   v.f = g_value_get_double (value);
258   
259   psppire_data_store_set_value (store, row, var, &v);
260
261   value_destroy (&v, var_get_width (var));
262 }
263
264 static void
265 psppire_data_editor_set_property (GObject         *object,
266                                   guint            prop_id,
267                                   const GValue    *value,
268                                   GParamSpec      *pspec)
269 {
270   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
271
272   switch (prop_id)
273     {
274     case PROP_SPLIT_WINDOW:
275       psppire_data_editor_split_window (de, g_value_get_boolean (value));
276       break;
277     case PROP_DATA_STORE:
278       if ( de->data_store)
279         {
280           g_signal_handlers_disconnect_by_func (de->data_store,
281                                                 G_CALLBACK (refresh_entry),
282                                                 de);
283           g_object_unref (de->data_store);
284         }
285
286       de->data_store = g_value_get_pointer (value);
287       g_object_ref (de->data_store);
288       g_print ("NEW STORE\n");
289
290       g_object_set (de->data_sheet, "data-model", de->data_store, NULL);
291       psppire_data_editor_refresh_model (de);
292
293       g_signal_connect_swapped (de->data_sheet, "value-changed",
294                                 G_CALLBACK (change_data_value), de->data_store);
295       
296       g_signal_connect_swapped (de->data_store, "case-changed",
297                                 G_CALLBACK (refresh_entry), de);
298
299       break;
300     case PROP_DICTIONARY:
301       if (de->dict)
302         g_object_unref (de->dict);
303       de->dict = g_value_get_pointer (value);
304       g_object_ref (de->dict);
305
306       g_object_set (de->data_sheet, "hmodel", de->dict, NULL);
307       g_object_set (de->var_sheet, "data-model", de->dict, NULL);
308       g_signal_connect_swapped (de->var_sheet, "value-changed",
309                                 G_CALLBACK (change_var_property), de->dict);
310
311       break;
312     case PROP_VALUE_LABELS:
313       break;
314     case PROP_UI_MANAGER:
315     default:
316       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
317       break;
318     };
319 }
320
321 static void
322 psppire_data_editor_get_property (GObject         *object,
323                                   guint            prop_id,
324                                   GValue          *value,
325                                   GParamSpec      *pspec)
326 {
327   PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
328
329   switch (prop_id)
330     {
331     case PROP_SPLIT_WINDOW:
332       g_value_set_boolean (value, de->split);
333       break;
334     case PROP_DATA_STORE:
335       g_value_set_pointer (value, de->data_store);
336       break;
337     case PROP_DICTIONARY:
338       g_value_set_pointer (value, de->dict);
339       break;
340     case PROP_VALUE_LABELS:
341       break;
342     case PROP_UI_MANAGER:
343       g_value_set_object (value, psppire_data_editor_get_ui_manager (de));
344       break;
345     default:
346       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
347       break;
348     }
349 }
350
351 static void
352 psppire_data_editor_switch_page (GtkNotebook     *notebook,
353                                  GtkWidget *w,
354                                  guint            page_num)
355 {
356   GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, w, page_num);
357   psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (notebook));
358 }
359
360 static void
361 psppire_data_editor_set_focus_child (GtkContainer *container,
362                                      GtkWidget    *widget)
363 {
364   GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget);
365   psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container));
366 }
367
368 static void
369 psppire_data_editor_class_init (PsppireDataEditorClass *klass)
370 {
371   GParamSpec *data_store_spec ;
372   GParamSpec *dict_spec ;
373   GParamSpec *value_labels_spec;
374   GParamSpec *split_window_spec;
375   GParamSpec *ui_manager_spec;
376   GObjectClass *object_class = G_OBJECT_CLASS (klass);
377   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
378   GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
379
380   parent_class = g_type_class_peek_parent (klass);
381
382   object_class->dispose = psppire_data_editor_dispose;
383   object_class->set_property = psppire_data_editor_set_property;
384   object_class->get_property = psppire_data_editor_get_property;
385
386   container_class->set_focus_child = psppire_data_editor_set_focus_child;
387
388   notebook_class->switch_page = psppire_data_editor_switch_page;
389
390   data_store_spec =
391     g_param_spec_pointer ("data-store",
392                           "Data Store",
393                           "A pointer to the data store associated with this editor",
394                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
395
396   g_object_class_install_property (object_class,
397                                    PROP_DATA_STORE,
398                                    data_store_spec);
399
400   dict_spec =
401     g_param_spec_pointer ("dictionary",
402                           "Dictionary",
403                           "A pointer to the dictionary associated with this editor",
404                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
405
406   g_object_class_install_property (object_class,
407                                    PROP_DICTIONARY,
408                                    dict_spec);
409
410   value_labels_spec =
411     g_param_spec_boolean ("value-labels",
412                          "Value Labels",
413                          "Whether or not the data sheet should display labels instead of values",
414                           FALSE,
415                          G_PARAM_WRITABLE | G_PARAM_READABLE);
416
417   g_object_class_install_property (object_class,
418                                    PROP_VALUE_LABELS,
419                                    value_labels_spec);
420
421
422   split_window_spec =
423     g_param_spec_boolean ("split",
424                           "Split Window",
425                           "True iff the data sheet is split",
426                           FALSE,
427                           G_PARAM_READABLE | G_PARAM_WRITABLE);
428
429   g_object_class_install_property (object_class,
430                                    PROP_SPLIT_WINDOW,
431                                    split_window_spec);
432
433   ui_manager_spec =
434     g_param_spec_object ("ui-manager",
435                          "UI Manager",
436                          "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.",
437                          GTK_TYPE_UI_MANAGER,
438                          G_PARAM_READABLE);
439   g_object_class_install_property (object_class,
440                                    PROP_UI_MANAGER,
441                                    ui_manager_spec);
442 }
443
444
445 static void
446 on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
447                                  PsppireDataEditor *de)
448 {
449   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
450                                  PSPPIRE_DATA_EDITOR_DATA_VIEW);
451
452   jmd_sheet_scroll_to (JMD_SHEET (de->data_sheet), dict_index, -1);
453 }
454
455 static void
456 on_data_sheet_var_double_clicked (JmdSheet *data_sheet, gint dict_index,
457                                  PsppireDataEditor *de)
458 {
459   gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
460                                  PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
461
462   jmd_sheet_scroll_to (JMD_SHEET (de->var_sheet), -1, dict_index);
463 }
464
465
466 /* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
467    active cell or cells. */
468 static void
469 refresh_entry (PsppireDataEditor *de)
470 {
471   g_print ("%s\n", __FUNCTION__);
472 }
473
474 static void
475 on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
476 {
477 }
478
479
480 static void
481 disconnect_data_sheets (PsppireDataEditor *de)
482 {
483 }
484
485 /* Called when the active cell or the selection in the data sheet changes */
486 static void
487 on_data_selection_change (PsppireDataEditor *de, JmdRange *sel)
488 {
489   gchar *ref_cell_text = NULL;
490
491   gint n_cases = abs (sel->end_y - sel->start_y) + 1;
492   gint n_vars = abs (sel->end_x - sel->start_x) + 1;
493
494   if (n_cases == 1 && n_vars == 1)
495     {
496       /* A single cell is selected */
497       const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x);
498       
499       ref_cell_text = g_strdup_printf (_("%d : %s"),
500                                        sel->start_y + 1, var_get_name (var));
501     }
502   else
503     {
504       struct string s;
505
506       /* The glib string library does not understand the ' printf modifier
507          on all platforms, but the "struct string" library does (because
508          Gnulib fixes that problem), so use the latter.  */
509       ds_init_empty (&s);
510       ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
511                      n_cases);
512       ds_put_byte (&s, ' ');
513       ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
514       ds_put_byte (&s, ' ');
515       ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
516                                    n_vars),
517                      n_vars);
518       ref_cell_text = ds_steal_cstr (&s);
519     }
520   
521   gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
522                        ref_cell_text ? ref_cell_text : "");
523   
524   g_free (ref_cell_text);
525 }
526
527
528 static void set_font_recursively (GtkWidget *w, gpointer data);
529
530 static void
531 psppire_data_editor_init (PsppireDataEditor *de)
532 {
533   GtkWidget *hbox;
534   gchar *fontname = NULL;
535
536   de->font = NULL;
537   de->ui_manager = NULL;
538   de->old_vbox_widget = NULL;
539
540   g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL);
541
542   de->cell_ref_label = gtk_label_new ("");
543   gtk_label_set_width_chars (GTK_LABEL (de->cell_ref_label), 25);
544   gtk_widget_set_valign (de->cell_ref_label, GTK_ALIGN_CENTER);
545
546   de->datum_entry = psppire_value_entry_new ();
547   g_signal_connect (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))),
548                     "activate", G_CALLBACK (on_datum_entry_activate), de);
549
550   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
551   gtk_box_pack_start (GTK_BOX (hbox), de->cell_ref_label, FALSE, FALSE, 0);
552   gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
553
554   de->split = FALSE;
555   de->data_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
556   GtkWidget *data_button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet));
557   gtk_button_set_label (GTK_BUTTON (data_button), _("Case"));
558   de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
559   gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
560   gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0);
561
562
563   g_signal_connect_swapped (de->data_sheet, "selection-changed",
564                     G_CALLBACK (on_data_selection_change), de);
565   
566   gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
567                             gtk_label_new_with_mnemonic (_("Data View")));
568
569   gtk_widget_show_all (de->vbox);
570
571   de->var_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
572
573   PsppireVarSheetHeader *vsh = g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL);
574   
575   g_object_set (de->var_sheet,
576                 "hmodel", vsh,
577                 "select-renderer-func", select_renderer_func,
578                 NULL);
579
580   
581   GtkWidget *var_button = jmd_sheet_get_button (JMD_SHEET (de->var_sheet));
582   gtk_button_set_label (GTK_BUTTON (var_button), _("Variable"));
583   
584   gtk_notebook_append_page (GTK_NOTEBOOK (de), de->var_sheet,
585                             gtk_label_new_with_mnemonic (_("Variable View")));
586
587   gtk_widget_show_all (de->var_sheet);
588   
589   g_signal_connect (de->var_sheet, "row-header-double-clicked",
590                     G_CALLBACK (on_var_sheet_var_double_clicked), de);
591
592   g_signal_connect (de->data_sheet, "column-header-double-clicked",
593                     G_CALLBACK (on_data_sheet_var_double_clicked), de);
594
595   g_object_set (de, "can-focus", FALSE, NULL);
596
597   if (psppire_conf_get_string (psppire_conf_new (),
598                            "Data Editor", "font",
599                                 &fontname) )
600     {
601       de->font = pango_font_description_from_string (fontname);
602       g_free (fontname);
603       set_font_recursively (GTK_WIDGET (de), de->font);
604     }
605
606   psppire_data_editor_update_ui_manager (de);
607 }
608
609 GtkWidget*
610 psppire_data_editor_new (PsppireDict *dict,
611                          PsppireDataStore *data_store)
612 {
613   return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
614                         "dictionary",  dict,
615                         "data-store",  data_store,
616                         NULL);
617 }
618 \f
619 /* Turns the visible grid on or off, according to GRID_VISIBLE, for DE's data
620    sheet(s) and variable sheet. */
621 void
622 psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
623 {
624   GtkTreeViewGridLines grid;
625
626   grid = (grid_visible
627           ? GTK_TREE_VIEW_GRID_LINES_BOTH
628           : GTK_TREE_VIEW_GRID_LINES_NONE);
629
630   pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
631 }
632
633
634 static void
635 set_font_recursively (GtkWidget *w, gpointer data)
636 {
637   PangoFontDescription *font_desc = data;
638
639   gtk_widget_override_font (w, font_desc);
640
641   if ( GTK_IS_CONTAINER (w))
642     gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc);
643 }
644
645 /* Sets FONT_DESC as the font used by the data sheet(s) and variable sheet. */
646 void
647 psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_desc)
648 {
649   gchar *font_name;
650   set_font_recursively (GTK_WIDGET (de), font_desc);
651
652   if (de->font)
653     pango_font_description_free (de->font);
654   de->font = pango_font_description_copy (font_desc);
655   font_name = pango_font_description_to_string (de->font);
656
657   psppire_conf_set_string (psppire_conf_new (),
658                            "Data Editor", "font",
659                            font_name);
660
661 }
662
663 /* If SPLIT is TRUE, splits DE's data sheet into four panes.
664    If SPLIT is FALSE, un-splits it into a single pane. */
665 void
666 psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
667 {
668   if (split == de->split)
669     return;
670
671   disconnect_data_sheets (de);
672
673   psppire_data_editor_refresh_model (de);
674
675   gtk_widget_show_all (de->vbox);
676
677   if (de->font)
678     set_font_recursively (GTK_WIDGET (de), de->font);
679
680   de->split = split;
681   g_object_notify (G_OBJECT (de), "split");
682   psppire_data_editor_update_ui_manager (de);
683 }
684
685 /* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
686    visible and selected in the active view in DE. */
687 void
688 psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
689 {
690 }
691
692
693 /* Returns the UI manager that should be merged into DE's toplevel widget's UI
694    manager to display menu items and toolbar items specific to DE's current
695    page and data sheet.
696
697    DE's toplevel widget can watch for changes by connecting to DE's
698    notify::ui-manager signal. */
699 GtkUIManager *
700 psppire_data_editor_get_ui_manager (PsppireDataEditor *de)
701 {
702   psppire_data_editor_update_ui_manager (de);
703   return de->ui_manager;
704 }
705
706 static void
707 psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
708 {
709   GtkUIManager *ui_manager;
710
711   ui_manager = NULL;
712
713   switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
714     {
715     case PSPPIRE_DATA_EDITOR_DATA_VIEW:
716       break;
717
718     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
719       break;
720
721     default:
722       /* This happens transiently in psppire_data_editor_init(). */
723       break;
724     }
725
726   if (ui_manager != de->ui_manager)
727     {
728       if (de->ui_manager)
729         g_object_unref (de->ui_manager);
730       if (ui_manager)
731         g_object_ref (ui_manager);
732       de->ui_manager = ui_manager;
733
734       g_object_notify (G_OBJECT (de), "ui-manager");
735     }
736 }