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