Added psppire-dialog and psppire-buttonbox widgets.
[pspp-builds.git] / src / ui / gui / psppire-var-select.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2007  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 #include <config.h>
21
22 #include "psppire-var-select.h"
23 #include "psppire-object.h"
24
25 #include "psppire-dict.h"
26
27 #include <gettext.h>
28
29 #define _(msgid) gettext (msgid)
30 #define N_(msgid) msgid
31
32
33 /* This object is an attempt to abstract a situation commonly found in PSPP
34    dialogs, where two widgets (typically GtkTreeViews) contain a list
35    of variables,  and the variables may be selected by the user and
36    transfered to between the widgets, in preparation for some
37    operation.
38
39    Currently it assumes that the first widget is  GtkTreeView and the
40    second is a GtkEntry (as required for the Weight Cases dialog).
41    It needs to be generalized further to make  it useful.
42 */
43
44 static void setup_dictionary_treeview (GtkTreeView *,
45                                        const PsppireDict *,
46                                        GtkSelectionMode);
47
48
49 /* --- prototypes --- */
50 static void psppire_var_select_class_init (PsppireVarSelectClass *);
51 static void psppire_var_select_init          (PsppireVarSelect *);
52 static void psppire_var_select_finalize   (GObject *);
53
54
55 enum  {VARIABLE_SELECTED,
56        DESELECT_ALL,
57        n_SIGNALS};
58
59 static guint signal[n_SIGNALS];
60
61
62 /* --- variables --- */
63 static GObjectClass     *parent_class = NULL;
64
65 /* --- functions --- */
66 /**
67  * psppire_var_select_get_type:
68  * @returns: the type ID for accelerator groups.
69  */
70 GType
71 psppire_var_select_get_type (void)
72 {
73   static GType object_type = 0;
74
75   if (!object_type)
76     {
77       static const GTypeInfo object_info = {
78         sizeof (PsppireVarSelectClass),
79         (GBaseInitFunc) NULL,
80         (GBaseFinalizeFunc) NULL,
81         (GClassInitFunc) psppire_var_select_class_init,
82         NULL,   /* class_finalize */
83         NULL,   /* class_data */
84         sizeof (PsppireVarSelect),
85         0,      /* n_preallocs */
86         (GInstanceInitFunc) psppire_var_select_init,
87       };
88
89       object_type = g_type_register_static (G_TYPE_PSPPIRE_OBJECT,
90                                             "PsppireVarSelect",
91                                             &object_info, 0);
92     }
93
94   return object_type;
95 }
96
97
98 static void
99 psppire_var_select_class_init (PsppireVarSelectClass *class)
100 {
101   GObjectClass *object_class = G_OBJECT_CLASS (class);
102
103   parent_class = g_type_class_peek_parent (class);
104
105
106   signal [VARIABLE_SELECTED] =
107     g_signal_new ("variable_selected",
108                   G_TYPE_FROM_CLASS (class),
109                   G_SIGNAL_RUN_FIRST,
110                   0,
111                   NULL, NULL,
112                   g_cclosure_marshal_VOID__INT,
113                   G_TYPE_NONE,
114                   1,
115                   G_TYPE_INT);
116
117
118   signal [DESELECT_ALL] =
119     g_signal_new ("deselect_all",
120                   G_TYPE_FROM_CLASS (class),
121                   G_SIGNAL_RUN_FIRST,
122                   0,
123                   NULL, NULL,
124                   g_cclosure_marshal_VOID__VOID,
125                   G_TYPE_NONE,
126                   0);
127
128   object_class->finalize = psppire_var_select_finalize;
129 }
130
131 static void
132 psppire_var_select_finalize (GObject *object)
133 {
134   PsppireVarSelect *vs = PSPPIRE_VAR_SELECT (object);
135
136   g_list_free (vs->list);
137
138   G_OBJECT_CLASS (parent_class)->finalize (object);
139 }
140
141 static void
142 psppire_var_select_init (PsppireVarSelect *vs)
143 {
144   vs->list = NULL;
145   vs->mode = GTK_SELECTION_SINGLE;
146 }
147
148 /* Return list of all the currently selected variables */
149 const GList *
150 psppire_var_select_get_variables (PsppireVarSelect *vs)
151 {
152   return vs->list;
153 }
154
155
156 static void
157 add_variable_to_selection (PsppireVarSelect *vs, struct variable *var)
158 {
159   gtk_entry_set_text (GTK_ENTRY (vs->dest), var_get_name (var) );
160
161   if ( vs->mode == GTK_SELECTION_SINGLE)
162     {
163       g_list_free (vs->list);
164       vs->list = NULL;
165     }
166   vs->list = g_list_append (vs->list, var);
167
168   g_signal_emit (vs, signal [VARIABLE_SELECTED], 0, var_get_dict_index (var));
169 }
170
171
172 /* Add VAR to the list of selected variables */
173 void
174 psppire_var_select_set_variable (PsppireVarSelect *vs,
175                                  struct variable *var)
176 {
177   add_variable_to_selection (vs, var);
178 }
179
180
181 static void
182 on_source_activate (GtkTreeView       *tree_view,
183                     GtkTreePath       *path,
184                     GtkTreeViewColumn *column,
185                     gpointer           user_data)
186
187 {
188   PsppireVarSelect *vs = user_data;
189   GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
190
191   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
192
193   GList *list = gtk_tree_selection_get_selected_rows (selection, &model);
194
195   while (list)
196     {
197       struct variable *var;
198       GtkTreeIter iter;
199       GtkTreePath *path = list->data;
200
201       gtk_tree_model_get_iter (model, &iter, path);
202
203       gtk_tree_model_get (model, &iter, DICT_TVM_COL_VAR, &var, -1);
204
205       add_variable_to_selection (vs, var);
206
207       list = list->next;
208     }
209 }
210
211
212 /**
213  * psppire_var_select_new:
214  * @returns: a new #PsppireVarSelect object
215  *
216  * Creates a new #PsppireVarSelect.
217  */
218 PsppireVarSelect*
219 psppire_var_select_new (GtkWidget *source, GtkWidget *dest,
220                         const PsppireDict *dict)
221 {
222   PsppireVarSelect *vs
223     = g_object_new (G_TYPE_PSPPIRE_VAR_SELECT, NULL);
224
225   GtkTreeSelection *src_selection;
226
227   vs->source = source;
228   vs->dest = dest;
229   vs->dict = dict;
230
231
232   setup_dictionary_treeview ( GTK_TREE_VIEW (source),
233                               vs->dict, vs->mode);
234
235
236   src_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (vs->source));
237
238   g_signal_connect (source, "row-activated",
239                     G_CALLBACK (on_source_activate), vs);
240
241   return vs;
242 }
243
244 void
245 psppire_var_select_deselect_all (PsppireVarSelect *vs)
246 {
247   g_list_free (vs->list);
248   vs->list = NULL;
249
250   gtk_entry_set_text ( GTK_ENTRY(vs->dest), "");
251
252   g_signal_emit (vs, signal [DESELECT_ALL], 0);
253 }
254
255
256 static void
257 setup_dictionary_treeview (GtkTreeView *treeview, const PsppireDict *dict,
258                            GtkSelectionMode mode)
259 {
260   /* Set up the dictionary treeview */
261   GtkTreeViewColumn *col;
262
263   GtkTreeSelection *selection =
264     gtk_tree_view_get_selection (treeview);
265
266   GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
267
268
269   gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (dict));
270
271   col = gtk_tree_view_column_new_with_attributes (_("Var"),
272                                                   renderer,
273                                                   "text",
274                                                   0,
275                                                   NULL);
276
277   /* FIXME: make this a value in terms of character widths */
278   g_object_set (col, "min-width",  100, NULL);
279
280   gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
281
282   gtk_tree_view_append_column (treeview, col);
283
284   gtk_tree_selection_set_mode (selection, mode);
285 }
286
287
288
289