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