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