+ PsppSheetViewColumn *tree_column;
+ GtkTreeModel *tree_model;
+ gpointer column_ptr;
+ bool ok;
+
+ /* Check that WIDGET is really visible on the screen before we
+ do anything else. This is a bug fix for a sticky situation:
+ when text_data_import_assistant() returns, it frees the data
+ necessary to compose the tool tip message, but there may be
+ a tool tip under preparation at that point (even if there is
+ no visible tool tip) that will call back into us a little
+ bit later. Perhaps the correct solution to this problem is
+ to make the data related to the tool tips part of a GObject
+ that only gets destroyed when all references are released,
+ but this solution appears to be effective too. */
+ if (!gtk_widget_get_mapped (widget))
+ return FALSE;
+
+ pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
+ wx, wy, &bx, &by);
+ if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
+ &path, &tree_column, NULL, NULL))
+ return FALSE;
+
+ column_ptr = g_object_get_data (G_OBJECT (tree_column), "column-number");
+ if (column_ptr == NULL)
+ return FALSE;
+ *column = GPOINTER_TO_INT (column_ptr) - 1;
+
+ pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
+ NULL);
+
+ tree_model = pspp_sheet_view_get_model (tree_view);
+ ok = gtk_tree_model_get_iter (tree_model, &iter, path);
+ gtk_tree_path_free (path);
+ if (!ok)
+ return FALSE;
+
+ *row = GPOINTER_TO_INT (iter.user_data);
+ return TRUE;
+}
+
+static gboolean
+on_query_var_tooltip (GtkWidget *widget, gint wx, gint wy,
+ gboolean keyboard_mode UNUSED,
+ GtkTooltip *tooltip, gpointer *user_data UNUSED)
+{
+ PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
+ PsppireDict *dict;
+ struct variable *var;
+ size_t row, column;
+
+ if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
+ return FALSE;
+
+ dict = psppire_var_sheet_get_dictionary (var_sheet);
+ g_return_val_if_fail (dict != NULL, FALSE);
+
+ if (row >= psppire_dict_get_var_cnt (dict))
+ {
+ gtk_tooltip_set_text (tooltip, _("Enter a variable name to add a "
+ "new variable."));
+ return TRUE;
+ }
+
+ var = psppire_dict_get_variable (dict, row);
+ g_return_val_if_fail (var != NULL, FALSE);
+
+ switch (column)
+ {
+ case VS_TYPE:
+ {
+ char text[FMT_STRING_LEN_MAX + 1];
+
+ fmt_to_string (var_get_print_format (var), text);
+ gtk_tooltip_set_text (tooltip, text);
+ return TRUE;
+ }
+
+ case VS_VALUES:
+ if (var_has_value_labels (var))
+ {
+ const struct val_labs *vls = var_get_value_labels (var);
+ const struct val_lab **labels = val_labs_sorted (vls);
+ struct string s;
+ size_t i;
+
+ ds_init_empty (&s);
+ for (i = 0; i < val_labs_count (vls); i++)
+ {
+ const struct val_lab *vl = labels[i];
+ gchar *vstr;
+
+ if (i >= 10 || ds_length (&s) > 500)
+ {
+ ds_put_cstr (&s, "...");
+ break;
+ }
+
+ vstr = value_to_text (vl->value, var);
+ ds_put_format (&s, _("{%s, %s}\n"), vstr,
+ val_lab_get_escaped_label (vl));
+ free (vstr);
+
+ }
+ ds_chomp_byte (&s, '\n');
+
+ gtk_tooltip_set_text (tooltip, ds_cstr (&s));
+ ds_destroy (&s);
+ free (labels);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}