Renamed function to reflect change of purpose from previous commit
[pspp-builds.git] / 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, 0,
102                 dict->dict,
103                 val, width);
104   msg_enable ();
105
106   return val;
107 }
108
109
110 GtkBuilder *
111 builder_new_real (const gchar *name)
112 {
113   GtkBuilder *builder = gtk_builder_new ();
114
115   GError *err = NULL;
116   if ( ! gtk_builder_add_from_file (builder, name,  &err))
117     {
118       g_critical ("Couldnt open user interface  file %s: %s", name, err->message);
119       g_clear_error (&err);
120     }
121
122   return builder;
123 }
124
125
126 GObject *
127 get_object_assert (GtkBuilder *builder, const gchar *name, GType type)
128 {
129   GObject *o = NULL;
130   g_assert (name);
131
132   o = gtk_builder_get_object (builder, name);
133
134   if ( !o )
135     g_critical ("Object \"%s\" could not be found\n", name);
136   else if ( ! g_type_is_a (G_OBJECT_TYPE (o), type))
137    {
138      g_critical ("Object \"%s\" was expected to have type %s, but in fact has type %s", 
139         name, g_type_name (type), G_OBJECT_TYPE_NAME (o));
140    }
141
142   return o;
143 }
144
145
146 GtkAction *
147 get_action_assert (GtkBuilder *builder, const gchar *name)
148 {
149   return GTK_ACTION (get_object_assert (builder, name, GTK_TYPE_ACTION));
150 }
151
152 GtkWidget *
153 get_widget_assert (GtkBuilder *builder, const gchar *name)
154 {
155   return GTK_WIDGET (get_object_assert (builder, name, GTK_TYPE_WIDGET));
156 }
157
158 /* This function must be used whenever a filename generated by glib,
159    (eg, from gtk_file_chooser_get_filename) and passed to the C library,
160    (eg through a pspp syntax string).
161 */
162 gchar *
163 convert_glib_filename_to_system_filename (const gchar *fname, GError **err)
164 {
165   gchar *output_name;
166
167 #ifdef G_OS_WIN32
168   const gchar *target_encoding;
169   gchar *utf8_name = NULL;
170
171   g_get_charset (&target_encoding);
172
173   output_name = g_convert (fname, -1, target_encoding,
174                         "UTF-8", NULL, NULL, err);
175 #else
176   output_name = xstrdup (fname);
177 #endif
178
179   return output_name;
180 }
181
182
183
184 #define _(msgid) gettext (msgid)
185 #define N_(msgid) msgid
186
187
188 static void
189 give_help (void)
190 {
191   GtkWidget *dialog;
192
193   dialog = gtk_message_dialog_new (NULL,
194                                    GTK_DIALOG_MODAL,
195                                    GTK_MESSAGE_INFO,
196                                    GTK_BUTTONS_CLOSE,
197                                    _("Sorry. The help system hasn't yet "
198                                      "been implemented."));
199   gtk_dialog_run (GTK_DIALOG (dialog));
200   gtk_widget_destroy (dialog);
201 }
202
203 void
204 connect_help (GtkBuilder *xml)
205 {
206   GSList *helps = gtk_builder_get_objects (xml);
207
208   GSList *i;
209   for ( i = helps; i ; i = g_slist_next (i))
210     {
211       GObject *o = i->data;
212       if ( GTK_IS_WIDGET (o) )
213         {
214           gchar *name = NULL;
215           gchar s[12] = {0};
216           g_object_get (o, "name", &name, NULL);
217
218           if ( name)
219             strncpy (s, name, 11);
220           s[11] = '\0';
221
222
223           if ( 0 == strcmp ("help_button", s))
224             {
225             g_signal_connect (o, "clicked", give_help, 0);
226             }
227         }
228     }
229
230   g_slist_free (helps);
231 }
232
233
234 /* Create a deep copy of SRC */
235 GtkListStore *
236 clone_list_store (const GtkListStore *src)
237 {
238   GtkTreeIter src_iter;
239   gboolean ok;
240   gint i;
241   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
242   GType *types = g_malloc (sizeof (*types) *  n_cols);
243
244   int row = 0;
245   GtkListStore *dest;
246
247   for (i = 0 ; i < n_cols; ++i )
248     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
249
250   dest = gtk_list_store_newv (n_cols, types);
251
252   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
253                                            &src_iter);
254        ok;
255        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
256     {
257       GtkTreeIter dest_iter;
258       gtk_list_store_append  (dest, &dest_iter);
259
260       for (i = 0 ; i < n_cols; ++i )
261         {
262           GValue val = {0};
263
264           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
265           gtk_list_store_set_value (dest, &dest_iter, i, &val);
266
267           g_value_unset (&val);
268         }
269       row++;
270     }
271
272   g_free (types);
273
274   return dest;
275 }
276
277
278
279
280 static gboolean 
281 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
282 {
283   *addr = NULL;
284
285   return FALSE;
286 }
287
288 void
289 paste_syntax_to_window (const gchar *syntax)
290 {
291   static GtkWidget *the_syntax_pasteboard = 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   gtk_text_buffer_insert_at_cursor (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer,
301                                     syntax, -1);
302
303   gtk_text_buffer_insert_at_cursor (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer,
304                                     "\n", 1);
305
306   gtk_widget_show (the_syntax_pasteboard);
307 }
308
309
310 /* gtk_box_pack_start_defaults is deprecated.
311    Therefore we roll our own until a better solution is found */
312 void
313 psppire_box_pack_start_defaults (GtkBox *box, GtkWidget *widget)
314 {
315   gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
316 }