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