a9b1139f18c6be631c82e73996c0baa0ffbdb747
[pspp] / src / ui / gui / psppire-means-layer.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2012  Free Software Foundation
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 "psppire-means-layer.h"
20 #include "psppire-selector.h"
21 #include "psppire-var-view.h"
22
23 #include <gtk/gtk.h>
24
25 #include "gettext.h"
26 #define _(msgid) gettext (msgid)
27 #define N_(msgid) msgid
28
29
30 static void psppire_means_layer_class_init    (PsppireMeansLayerClass *class);
31 static void psppire_means_layer_init          (PsppireMeansLayer      *window);
32
33 G_DEFINE_TYPE (PsppireMeansLayer, psppire_means_layer, GTK_TYPE_VBOX);
34
35 static GObjectClass *parent_class = NULL;
36
37 static void
38 psppire_means_layer_dispose (GObject *obj)
39 {
40   PsppireMeansLayer *w = (PsppireMeansLayer *)obj;
41
42   if (w->dispose_has_run)
43     return;
44
45   /* Make sure dispose does not run twice. */
46   w->dispose_has_run = TRUE;
47
48   g_ptr_array_unref (w->layer);
49
50   /* Chain up to the parent class */
51   G_OBJECT_CLASS (parent_class)->dispose (obj);
52 }
53
54
55 static void 
56 psppire_means_layer_class_init    (PsppireMeansLayerClass *class)
57 {
58   GObjectClass *object_class = G_OBJECT_CLASS (class);
59   parent_class = g_type_class_peek_parent (class);
60
61
62   object_class->dispose = psppire_means_layer_dispose;
63 }
64
65 static void
66 update (PsppireMeansLayer *ml)
67 {
68   gchar *l;
69
70   if (!gtk_widget_get_realized (GTK_WIDGET (ml)))
71     return;
72
73   l = g_strdup_printf (_("Layer %d of %d"),
74                               ml->current_layer + 1, ml->n_layers);
75   
76   gtk_label_set_text (GTK_LABEL (ml->label), l);
77   g_free (l);
78
79   gtk_widget_set_sensitive (ml->back, ml->current_layer > 0);
80   gtk_widget_set_sensitive (ml->forward,
81                             psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (ml->var_view),
82                                                              NULL));
83 }
84
85 static void
86 on_forward (PsppireMeansLayer *ml)
87 {
88   ml->current_layer++;
89   if (ml->current_layer >= ml->n_layers)
90     {
91       GtkTreeModel *tm;
92       psppire_var_view_clear (PSPPIRE_VAR_VIEW (ml->var_view));
93       tm = gtk_tree_view_get_model (GTK_TREE_VIEW (ml->var_view));
94       g_ptr_array_add (ml->layer, tm);
95       g_object_ref (tm);
96       ml->n_layers = ml->current_layer + 1;      
97     }
98   else
99     {
100       GtkTreeModel *tm = g_ptr_array_index (ml->layer, ml->current_layer);
101       gtk_tree_view_set_model (GTK_TREE_VIEW (ml->var_view), tm);
102     }
103 }
104
105 static void
106 on_back (PsppireMeansLayer *ml)
107 {
108   GtkTreeModel *tm;
109   g_return_if_fail (ml->current_layer > 0);
110   ml->current_layer--;
111
112   tm = g_ptr_array_index (ml->layer, ml->current_layer);
113   gtk_tree_view_set_model (GTK_TREE_VIEW (ml->var_view), tm);
114 }
115
116
117 static void 
118 psppire_means_layer_init  (PsppireMeansLayer      *ml)
119 {
120   GtkWidget *hbox_upper = gtk_hbox_new (FALSE, 5);
121   GtkWidget *hbox_lower = gtk_hbox_new (FALSE, 5);
122   GtkWidget *alignment = gtk_alignment_new (0, 0.5, 0, 0);
123   GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
124
125   ml->dispose_has_run = FALSE;
126   ml->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
127   ml->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
128   ml->var_view = psppire_var_view_new ();
129   ml->selector = psppire_selector_new ();
130   ml->label = gtk_label_new ("");
131
132   g_signal_connect_swapped (ml->forward, "clicked", G_CALLBACK (on_forward),
133                             ml);
134
135   g_signal_connect_swapped (ml->back, "clicked", G_CALLBACK (on_back), ml);
136
137   g_signal_connect_swapped (ml->selector, "selected", G_CALLBACK (update), ml);
138   g_signal_connect_swapped (ml->selector, "de-selected", G_CALLBACK (update),
139                             ml);
140
141   g_object_set (ml->var_view, "headers-visible", FALSE, NULL);
142   g_object_set (sw,
143                 "shadow-type", GTK_SHADOW_ETCHED_IN,
144                 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
145                 NULL);
146
147   g_object_set (ml->selector, "dest-widget", ml->var_view, NULL);
148   g_signal_connect_swapped (ml->var_view, "notify::model", G_CALLBACK (update), ml);
149
150   gtk_box_pack_start (GTK_BOX (hbox_upper), ml->back, FALSE, FALSE, 5);
151   gtk_box_pack_start (GTK_BOX (hbox_upper), ml->label, TRUE, FALSE, 5);
152   gtk_box_pack_start (GTK_BOX (hbox_upper), ml->forward, FALSE, FALSE, 5);
153
154   gtk_box_pack_start (GTK_BOX (hbox_lower), alignment, FALSE, FALSE, 5);
155   gtk_container_add (GTK_CONTAINER (alignment), ml->selector);
156   gtk_box_pack_start (GTK_BOX (hbox_lower), sw, TRUE, TRUE, 5);
157   gtk_container_add (GTK_CONTAINER (sw), ml->var_view);
158
159   gtk_box_pack_start (GTK_BOX (ml), hbox_upper, FALSE, FALSE, 5);
160   gtk_box_pack_start (GTK_BOX (ml), hbox_lower, TRUE, TRUE, 5);
161
162
163
164   ml->n_layers = 1;
165   ml->current_layer = 0;
166   ml->layer = g_ptr_array_new_full (3, g_object_unref);
167
168   /* Add a model and take a reference to it */
169   g_ptr_array_add (ml->layer, gtk_tree_view_get_model (GTK_TREE_VIEW (ml->var_view)));
170   g_object_ref (g_ptr_array_index (ml->layer, ml->current_layer));
171
172   update (ml);
173
174   gtk_widget_show_all (hbox_upper);
175   gtk_widget_show_all (hbox_lower);
176 }
177
178 GtkWidget *
179 psppire_means_layer_new (void)
180 {
181   return GTK_WIDGET (g_object_new (psppire_means_layer_get_type (), NULL));
182 }
183
184
185 void
186 psppire_means_layer_set_source (PsppireMeansLayer *ml, GtkWidget *w)
187 {
188   g_object_set (ml->selector, "source-widget", w, NULL);
189 }
190
191
192 void
193 psppire_means_layer_clear (PsppireMeansLayer *ml)
194 {
195   ml->n_layers = 1;
196   ml->current_layer = 0;
197   psppire_var_view_clear (PSPPIRE_VAR_VIEW (ml->var_view));
198 }
199
200
201 GtkTreeModel *
202 psppire_means_layer_get_model_n (PsppireMeansLayer *ml, gint n)
203 {
204   return g_ptr_array_index (ml->layer, n);
205 }