data-in: Eliminate "implied_decimals" parameter from data_in().
[pspp] / src / ui / gui / helper.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010  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 /* This file is a rubbish bin where stuff gets put when it doesn't seem to
19    belong anywhere else.
20 */
21 #include <config.h>
22
23 #include        <glib-object.h>
24
25 #include <glib.h>
26 #include "helper.h"
27 #include <data/format.h>
28 #include <data/data-in.h>
29 #include <data/data-out.h>
30 #include <data/dictionary.h>
31 #include <data/casereader-provider.h>
32 #include <libpspp/message.h>
33 #include "psppire-syntax-window.h"
34 #include <gtk/gtkbuilder.h>
35 #include <libpspp/i18n.h>
36
37 #include <ctype.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <data/settings.h>
41
42 #include "psppire-data-store.h"
43 #include "psppire.h"
44
45 #include "gl/configmake.h"
46 #include "xalloc.h"
47
48 #include <gettext.h>
49
50 /* Formats a value according to FORMAT
51    The returned string must be freed when no longer required */
52 gchar *
53 value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format)
54 {
55   gchar *s = 0;
56
57   s = data_out (&v, dict_get_encoding (dict->dict),  &format);
58   g_strchug (s);
59
60   return s;
61 }
62
63
64 /* Converts TEXT to a value.
65
66    VAL will be initialised and filled by this function.
67    It is the caller's responsibility to destroy VAL when no longer needed.
68    VAR and DICT must be the variable and dictionary with which VAL
69    is associated.
70
71    On success, VAL is returned, NULL otherwise.
72 */
73 union value *
74 text_to_value (const gchar *text,
75                const PsppireDict *dict,
76                const struct variable *var,
77                union value *val)
78 {
79   const struct fmt_spec *format = var_get_print_format (var);
80   int width = var_get_width (var);
81
82   if ( format->type != FMT_A)
83     {
84       if ( ! text ) return NULL;
85
86       {
87         const gchar *s = text;
88         while (*s)
89           {
90             if ( !isspace (*s))
91               break;
92             s++;
93           }
94
95         if ( !*s) return NULL;
96       }
97     }
98
99   value_init (val, width);
100   msg_disable ();
101   data_in (ss_cstr (text), UTF8, format->type, 0, 0, dict->dict, val, width);
102   msg_enable ();
103
104   return val;
105 }
106
107
108 GtkBuilder *
109 builder_new_real (const gchar *name)
110 {
111   GtkBuilder *builder = gtk_builder_new ();
112
113   GError *err = NULL;
114   if ( ! gtk_builder_add_from_file (builder, name,  &err))
115     {
116       g_critical ("Couldnt open user interface  file %s: %s", name, err->message);
117       g_clear_error (&err);
118     }
119
120   return builder;
121 }
122
123
124 GObject *
125 get_object_assert (GtkBuilder *builder, const gchar *name, GType type)
126 {
127   GObject *o = NULL;
128   g_assert (name);
129
130   o = gtk_builder_get_object (builder, name);
131
132   if ( !o )
133     g_critical ("Object `%s' could not be found\n", name);
134   else if ( ! g_type_is_a (G_OBJECT_TYPE (o), type))
135    {
136      g_critical ("Object `%s' was expected to have type %s, but in fact has type %s", 
137         name, g_type_name (type), G_OBJECT_TYPE_NAME (o));
138    }
139
140   return o;
141 }
142
143
144 GtkAction *
145 get_action_assert (GtkBuilder *builder, const gchar *name)
146 {
147   return GTK_ACTION (get_object_assert (builder, name, GTK_TYPE_ACTION));
148 }
149
150 GtkWidget *
151 get_widget_assert (GtkBuilder *builder, const gchar *name)
152 {
153   return GTK_WIDGET (get_object_assert (builder, name, GTK_TYPE_WIDGET));
154 }
155
156 /* This function must be used whenever a filename generated by glib,
157    (eg, from gtk_file_chooser_get_filename) and passed to the C library,
158    (eg through a pspp syntax string).
159 */
160 gchar *
161 convert_glib_filename_to_system_filename (const gchar *fname, GError **err)
162 {
163   gchar *output_name;
164
165 #ifdef G_OS_WIN32
166   const gchar *target_encoding;
167   gchar *utf8_name = NULL;
168
169   g_get_charset (&target_encoding);
170
171   output_name = g_convert (fname, -1, target_encoding,
172                         "UTF-8", NULL, NULL, err);
173 #else
174   output_name = xstrdup (fname);
175 #endif
176
177   return output_name;
178 }
179
180
181
182 #define _(msgid) gettext (msgid)
183 #define N_(msgid) msgid
184
185
186 static void
187 give_help (void)
188 {
189   GtkWidget *dialog;
190
191   dialog = gtk_message_dialog_new (NULL,
192                                    GTK_DIALOG_MODAL,
193                                    GTK_MESSAGE_INFO,
194                                    GTK_BUTTONS_CLOSE,
195                                    _("Sorry. The help system hasn't yet "
196                                      "been implemented."));
197   gtk_dialog_run (GTK_DIALOG (dialog));
198   gtk_widget_destroy (dialog);
199 }
200
201 void
202 connect_help (GtkBuilder *xml)
203 {
204   GSList *helps = gtk_builder_get_objects (xml);
205
206   GSList *i;
207   for ( i = helps; i ; i = g_slist_next (i))
208     {
209       GObject *o = i->data;
210       if ( GTK_IS_WIDGET (o) )
211         {
212           gchar *name = NULL;
213           gchar s[12] = {0};
214           g_object_get (o, "name", &name, NULL);
215
216           if ( name)
217             strncpy (s, name, 11);
218           s[11] = '\0';
219
220
221           if ( 0 == strcmp ("help_button", s))
222             {
223             g_signal_connect (o, "clicked", give_help, 0);
224             }
225         }
226     }
227
228   g_slist_free (helps);
229 }
230
231
232 /* Create a deep copy of SRC */
233 GtkListStore *
234 clone_list_store (const GtkListStore *src)
235 {
236   GtkTreeIter src_iter;
237   gboolean ok;
238   gint i;
239   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
240   GType *types = g_malloc (sizeof (*types) *  n_cols);
241
242   int row = 0;
243   GtkListStore *dest;
244
245   for (i = 0 ; i < n_cols; ++i )
246     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
247
248   dest = gtk_list_store_newv (n_cols, types);
249
250   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
251                                            &src_iter);
252        ok;
253        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
254     {
255       GtkTreeIter dest_iter;
256       gtk_list_store_append  (dest, &dest_iter);
257
258       for (i = 0 ; i < n_cols; ++i )
259         {
260           GValue val = {0};
261
262           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
263           gtk_list_store_set_value (dest, &dest_iter, i, &val);
264
265           g_value_unset (&val);
266         }
267       row++;
268     }
269
270   g_free (types);
271
272   return dest;
273 }
274
275
276
277
278 static gboolean 
279 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
280 {
281   *addr = NULL;
282
283   return FALSE;
284 }
285
286 void
287 paste_syntax_to_window (const gchar *syntax)
288 {
289   static GtkWidget *the_syntax_pasteboard = NULL;
290
291   GtkTextBuffer *buffer = NULL;
292
293   if ( NULL == the_syntax_pasteboard)
294     {
295       the_syntax_pasteboard = psppire_syntax_window_new ();
296       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
297                         &the_syntax_pasteboard);
298     }
299
300   buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);
301
302   gtk_text_buffer_begin_user_action (buffer);
303   gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
304   gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
305   gtk_text_buffer_end_user_action (buffer);
306
307   gtk_widget_show (the_syntax_pasteboard);
308 }
309
310
311 /* gtk_box_pack_start_defaults is deprecated.
312    Therefore we roll our own until a better solution is found */
313 void
314 psppire_box_pack_start_defaults (GtkBox *box, GtkWidget *widget)
315 {
316   gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
317 }