Config option to prefer variable labels vs. names
[pspp-builds.git] / src / ui / gui / dict-display.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007  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
18 #include <config.h>
19 #include <gettext.h>
20 #include <gtk/gtk.h>
21
22 #include "psppire-conf.h"
23 #include "dict-display.h"
24
25 #include "psppire-dict.h"
26 #include "helper.h"
27 #include <data/variable.h>
28 #include <data/format.h>
29
30 #define _(msgid) gettext (msgid)
31 #define N_(msgid) msgid
32
33
34 /* A GtkTreeModelFilterVisibleFunc to filter lines in the treeview */
35 static gboolean
36 filter_variables (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
37 {
38   var_predicate_func *predicate = data;
39   struct variable *var;
40   PsppireDict *dict = PSPPIRE_DICT (model);
41
42   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
43
44   gint *idx = gtk_tree_path_get_indices (path);
45
46   var =  psppire_dict_get_variable (dict, *idx);
47
48   gtk_tree_path_free (path);
49
50   return predicate (var);
51 }
52
53 /* A GtkTreeCellDataFunc which sets the icon appropriate to the type
54    of variable */
55 static void
56 var_icon_cell_data_func (GtkTreeViewColumn *col,
57                        GtkCellRenderer *cell,
58                        GtkTreeModel *model,
59                        GtkTreeIter *iter,
60                        gpointer data)
61 {
62   struct variable *var;
63   gtk_tree_model_get (model, iter, DICT_TVM_COL_VAR, &var, -1);
64
65   if ( var_is_alpha (var))
66     {
67       g_object_set (cell, "stock-id", "var-string", NULL);
68     }
69   else
70     {
71       const struct fmt_spec *fs = var_get_write_format (var);
72       int cat = fmt_get_category (fs->type);
73       switch ( var_get_measure (var))
74         {
75         case MEASURE_NOMINAL:
76           g_object_set (cell, "stock-id", "var-nominal", NULL);
77           break;
78         case MEASURE_ORDINAL:
79           g_object_set (cell, "stock-id", "var-ordinal", NULL);
80           break;
81         case MEASURE_SCALE:
82           if ( ( FMT_CAT_DATE | FMT_CAT_TIME ) & cat )
83             g_object_set (cell, "stock-id", "var-date-scale", NULL);
84           else
85             g_object_set (cell, "stock-id", "var-scale", NULL);
86           break;
87         default:
88           g_assert_not_reached ();
89         };
90     }
91 }
92
93
94 void
95 get_base_model (GtkTreeModel *top_model, GtkTreeIter *top_iter,
96                 GtkTreeModel **model, GtkTreeIter *iter
97                 )
98 {
99   *model = top_model;
100   *iter = *top_iter;
101   while (GTK_IS_TREE_MODEL_FILTER (*model))
102     {
103       GtkTreeIter parent_iter = *iter;
104       GtkTreeModelFilter *parent_model = GTK_TREE_MODEL_FILTER (*model);
105
106       *model = gtk_tree_model_filter_get_model (parent_model);
107
108       gtk_tree_model_filter_convert_iter_to_child_iter (parent_model,
109                                                         iter,
110                                                         &parent_iter);
111     }
112
113   g_assert (PSPPIRE_IS_DICT (*model));
114 }
115
116 /* A GtkTreeCellDataFunc which renders the name and/or label of the
117    variable */
118 static void
119 var_description_cell_data_func (GtkTreeViewColumn *col,
120                                 GtkCellRenderer *cell,
121                                 GtkTreeModel *top_model,
122                                 GtkTreeIter *top_iter,
123                                 gpointer data)
124 {
125   struct variable *var;
126   GtkTreeIter iter;
127   GtkTreeModel *model;
128   gboolean prefer_labels = FALSE;
129
130   PsppireConf *conf = psppire_conf_new ();
131
132   psppire_conf_get_boolean (conf, "dialog-boxes", "prefer-labels",
133                             &prefer_labels);
134
135   get_base_model (top_model, top_iter, &model, &iter);
136
137   g_assert (PSPPIRE_IS_DICT (model));
138
139
140   gtk_tree_model_get (model,
141                       &iter, DICT_TVM_COL_VAR, &var, -1);
142
143   if ( var_has_label (var) && prefer_labels)
144     {
145       gchar *text = g_strdup_printf (
146                                      "<span stretch=\"condensed\">%s</span>",
147                                      var_get_label (var));
148
149       char *utf8 = pspp_locale_to_utf8 (text, -1, NULL);
150
151       g_free (text);
152       g_object_set (cell, "markup", utf8, NULL);
153       g_free (utf8);
154     }
155   else
156     {
157       char *name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
158       g_object_set (cell, "text", name, NULL);
159       g_free (name);
160     }
161 }
162
163
164 /* Sets the tooltip to be the name of the variable under the cursor */
165 static gboolean
166 set_tooltip_for_variable (GtkTreeView  *treeview,
167                           gint        x,
168                           gint        y,
169                           gboolean    keyboard_mode,
170                           GtkTooltip *tooltip,
171                           gpointer    user_data)
172
173 {
174   gint bx, by;
175   GtkTreeIter iter;
176   GtkTreePath *path;
177   GtkTreeModel *tree_model;
178   struct variable *var = NULL;
179   gboolean ok;
180
181
182   gtk_tree_view_convert_widget_to_bin_window_coords (treeview,
183                                                      x, y, &bx, &by);
184
185   if (!gtk_tree_view_get_path_at_pos (treeview, bx, by,
186                                       &path, NULL, NULL, NULL))
187     return FALSE;
188
189   tree_model = gtk_tree_view_get_model (treeview);
190
191
192   gtk_tree_view_set_tooltip_row (treeview, tooltip, path);
193
194   ok = gtk_tree_model_get_iter (tree_model, &iter, path);
195
196   gtk_tree_path_free (path);
197   if (!ok)
198     return FALSE;
199
200
201   gtk_tree_model_get (tree_model, &iter, DICT_TVM_COL_VAR,  &var, -1);
202
203   if ( ! var_has_label (var))
204     return FALSE;
205
206   {
207     gchar *tip ;
208     gboolean prefer_labels = FALSE;
209
210     PsppireConf *conf = psppire_conf_new ();
211
212     psppire_conf_get_boolean (conf, "dialog-boxes", "prefer-labels",
213                               &prefer_labels);
214
215     if ( prefer_labels )
216       tip = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
217     else
218       tip = pspp_locale_to_utf8 (var_get_label (var), -1, NULL);
219
220     gtk_tooltip_set_text (tooltip, tip);
221
222     g_free (tip);
223   }
224
225   return TRUE;
226 }
227
228    /* Sets up TREEVIEW to display the variables of DICT.
229    MODE is the selection mode for TREEVIEW.
230    PREDICATE determines which variables should be visible, or NULL if
231    all are to be visible.
232  */
233 void
234 attach_dictionary_to_treeview (GtkTreeView *treeview, PsppireDict *dict,
235                                GtkSelectionMode mode,
236                                var_predicate_func *predicate
237                                )
238 {
239   GtkTreeViewColumn *col;
240
241   GtkTreeSelection *selection =
242     gtk_tree_view_get_selection (treeview);
243
244   GtkCellRenderer *renderer;
245
246   GtkTreeModel *model ;
247
248   if ( predicate )
249     {
250       model = gtk_tree_model_filter_new (GTK_TREE_MODEL (dict),
251                                           NULL);
252
253       gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
254                                               filter_variables,
255                                               predicate,
256                                               NULL);
257     }
258   else
259     {
260       model = GTK_TREE_MODEL (dict);
261     }
262
263   gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), model);
264
265
266   col = gtk_tree_view_column_new ();
267   gtk_tree_view_column_set_title (col, _("Variable"));
268
269   renderer = gtk_cell_renderer_pixbuf_new ();
270   gtk_tree_view_column_pack_start (col, renderer, FALSE);
271
272   gtk_tree_view_column_set_cell_data_func (col, renderer,
273                                            var_icon_cell_data_func,
274                                            NULL, NULL);
275
276
277   renderer = gtk_cell_renderer_text_new ();
278   gtk_tree_view_column_pack_start (col, renderer, TRUE);
279   gtk_tree_view_column_set_cell_data_func (col, renderer,
280                                            var_description_cell_data_func,
281                                            NULL, NULL);
282
283   g_object_set (renderer, "ellipsize-set", TRUE, NULL);
284   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_MIDDLE, NULL);
285
286   gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
287
288   /* FIXME: make this a value in terms of character widths */
289   gtk_tree_view_column_set_min_width (col, 150);
290
291   gtk_tree_view_append_column (treeview, col);
292
293   gtk_tree_selection_set_mode (selection, mode);
294
295   g_object_set (treeview, "has-tooltip", TRUE, NULL);
296
297 #if GTK_CHECK_VERSION (2, 12, 0)
298   g_signal_connect (treeview, "query-tooltip", G_CALLBACK (set_tooltip_for_variable), NULL);
299 #endif
300 }
301
302
303 void
304 insert_source_row_into_entry (GtkTreeIter iter,
305                               GtkWidget *dest,
306                               GtkTreeModel *model,
307                               gpointer data
308                               )
309 {
310   GtkTreePath *path;
311   GtkTreeModel *dict;
312   gint *idx;
313   struct variable *var;
314   GtkTreeIter dict_iter;
315   gchar *name;
316
317   g_return_if_fail (GTK_IS_ENTRY(dest));
318
319   get_base_model (model, &iter, &dict, &dict_iter);
320
321   path = gtk_tree_model_get_path (GTK_TREE_MODEL (dict), &dict_iter);
322
323   idx = gtk_tree_path_get_indices (path);
324
325   var =  psppire_dict_get_variable (PSPPIRE_DICT (dict), *idx);
326
327   gtk_tree_path_free (path);
328
329   name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
330   gtk_entry_set_text (GTK_ENTRY (dest),  name);
331   g_free (name);
332 }
333
334
335
336 void
337 insert_source_row_into_tree_view (GtkTreeIter iter,
338                                   GtkWidget *dest,
339                                   GtkTreeModel *model,
340                                   gpointer data
341                                   )
342 {
343   GtkTreePath *path;
344   GtkTreeIter dest_iter;
345   GtkTreeIter dict_iter;
346   gint *row ;
347   GtkTreeModel *destmodel = gtk_tree_view_get_model ( GTK_TREE_VIEW (dest));
348
349   GtkTreeModel *dict;
350
351
352   get_base_model (model, &iter, &dict, &dict_iter);
353
354   path = gtk_tree_model_get_path (dict, &dict_iter);
355
356   row = gtk_tree_path_get_indices (path);
357
358   gtk_list_store_append (GTK_LIST_STORE (destmodel),  &dest_iter);
359   gtk_list_store_set (GTK_LIST_STORE (destmodel), &dest_iter, 0, *row, -1);
360
361   gtk_tree_path_free (path);
362 }
363
364
365 gboolean
366 is_currently_in_entry (GtkTreeModel *model, GtkTreeIter *iter,
367                        PsppireSelector *selector)
368 {
369   gboolean result;
370   gchar *name;
371   GtkTreeIter dict_iter;
372   GtkTreeModel *dict;
373   struct variable *var;
374   gint dict_index;
375   gint *indeces;
376   GtkTreePath *path;
377   const gchar *text =   gtk_entry_get_text (GTK_ENTRY (selector->dest));
378
379   get_base_model (model, iter, &dict, &dict_iter);
380
381   path = gtk_tree_model_get_path (dict, &dict_iter);
382
383   indeces = gtk_tree_path_get_indices (path);
384
385   dict_index = indeces [0];
386
387   var = psppire_dict_get_variable (PSPPIRE_DICT (dict), dict_index);
388
389   gtk_tree_path_free (path);
390
391   name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
392   result = ( 0 == strcmp (text, name));
393   g_free (name);
394
395   return result;
396 }
397
398