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