New file: builder-wrapper.h and builder-wrapper.c
[pspp-builds.git] / src / ui / gui / helper.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010, 2011, 2012  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 /* This function must be used whenever a filename generated by glib,
115    (eg, from gtk_file_chooser_get_filename) and passed to the C library,
116    (eg through a pspp syntax string).
117 */
118 gchar *
119 convert_glib_filename_to_system_filename (const gchar *fname, GError **err)
120 {
121   gchar *output_name;
122
123 #ifdef G_OS_WIN32
124   const gchar *target_encoding;
125   gchar *utf8_name = NULL;
126
127   g_get_charset (&target_encoding);
128
129   output_name = g_convert (fname, -1, target_encoding,
130                         "UTF-8", NULL, NULL, err);
131 #else
132   output_name = xstrdup (fname);
133 #endif
134
135   return output_name;
136 }
137
138
139
140 #define _(msgid) gettext (msgid)
141 #define N_(msgid) msgid
142
143
144 static void
145 give_help (void)
146 {
147   GtkWidget *dialog;
148
149   dialog = gtk_message_dialog_new (NULL,
150                                    GTK_DIALOG_MODAL,
151                                    GTK_MESSAGE_INFO,
152                                    GTK_BUTTONS_CLOSE,
153                                    _("Sorry. The help system hasn't yet "
154                                      "been implemented."));
155   gtk_dialog_run (GTK_DIALOG (dialog));
156   gtk_widget_destroy (dialog);
157 }
158
159 void
160 connect_help (GtkBuilder *xml)
161 {
162   GSList *helps = gtk_builder_get_objects (xml);
163
164   GSList *i;
165   for ( i = helps; i ; i = g_slist_next (i))
166     {
167       GObject *o = i->data;
168       if ( GTK_IS_WIDGET (o) )
169         {
170           const gchar *name = gtk_buildable_get_name (GTK_BUILDABLE (o));
171           gchar s[12] = {0};
172
173           if ( name)
174             strncpy (s, name, 11);
175           s[11] = '\0';
176
177
178           if ( 0 == strcmp ("help_button", s))
179             {
180             g_signal_connect (o, "clicked", give_help, 0);
181             }
182         }
183     }
184
185   g_slist_free (helps);
186 }
187
188
189 /* Create a deep copy of SRC */
190 GtkListStore *
191 clone_list_store (const GtkListStore *src)
192 {
193   GtkTreeIter src_iter;
194   gboolean ok;
195   gint i;
196   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
197   GType *types = g_malloc (sizeof (*types) *  n_cols);
198
199   int row = 0;
200   GtkListStore *dest;
201
202   for (i = 0 ; i < n_cols; ++i )
203     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
204
205   dest = gtk_list_store_newv (n_cols, types);
206
207   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
208                                            &src_iter);
209        ok;
210        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
211     {
212       GtkTreeIter dest_iter;
213       gtk_list_store_append  (dest, &dest_iter);
214
215       for (i = 0 ; i < n_cols; ++i )
216         {
217           GValue val = {0};
218
219           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
220           gtk_list_store_set_value (dest, &dest_iter, i, &val);
221
222           g_value_unset (&val);
223         }
224       row++;
225     }
226
227   g_free (types);
228
229   return dest;
230 }
231
232
233
234
235 static gboolean 
236 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
237 {
238   *addr = NULL;
239
240   return FALSE;
241 }
242
243 char *
244 paste_syntax_to_window (gchar *syntax)
245 {
246   static GtkWidget *the_syntax_pasteboard = NULL;
247
248   GtkTextBuffer *buffer = NULL;
249
250   if ( NULL == the_syntax_pasteboard)
251     {
252       the_syntax_pasteboard = psppire_syntax_window_new (NULL);
253       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
254                         &the_syntax_pasteboard);
255     }
256
257   buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);
258
259   gtk_text_buffer_begin_user_action (buffer);
260   gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
261   gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
262   gtk_text_buffer_end_user_action (buffer);
263
264   gtk_widget_show (the_syntax_pasteboard);
265
266   return syntax;
267 }
268
269
270 /* gtk_box_pack_start_defaults is deprecated.
271    Therefore we roll our own until a better solution is found */
272 void
273 psppire_box_pack_start_defaults (GtkBox *box, GtkWidget *widget)
274 {
275   gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
276 }