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