refactor
[pspp] / src / ui / gui / helper.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010, 2011, 2012, 2013  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
44 #include "gl/configmake.h"
45 #include "xalloc.h"
46
47 #include <gettext.h>
48
49 /* Formats a value according to VAR's print format and strips white space
50    appropriately for VAR's type.  That is, if VAR is numeric, strips leading
51    white space (because numbers are right-justified within their fields), and
52    if VAR is string, strips trailing white space (because spaces pad out string
53    values on the right).
54
55    Returns an allocated string.  The returned string must be freed when no
56    longer required. */
57 gchar *
58 value_to_text (union value v, const struct variable *var)
59 {
60   return value_to_text__ (v, var_get_print_format (var),
61                           var_get_encoding (var));
62 }
63
64 /* Formats a value with format FORMAT and strips white space appropriately for
65    FORMATs' type.  That is, if FORMAT is numeric, strips leading white space
66    (because numbers are right-justified within their fields), and if FORMAT is
67    string, strips trailing white space (because spaces pad out string values on
68    the right).
69
70    Returns an allocated string.  The returned string must be freed when no
71    longer required. */
72 gchar *
73 value_to_text__ (union value v,
74                  const struct fmt_spec *format, const char *encoding)
75 {
76   gchar *s;
77
78   s = data_out_stretchy (&v, encoding, format, settings_get_fmt_settings (),
79                          NULL);
80   if (fmt_is_numeric (format->type))
81     g_strchug (s);
82   else
83     g_strchomp (s);
84
85   return s;
86 }
87
88 /* Converts TEXT to a value.
89
90    VAL will be initialised and filled by this function.
91    It is the caller's responsibility to destroy VAL when no longer needed.
92    VAR must be the variable with which VAL is associated.
93
94    On success, VAL is returned, NULL otherwise.
95 */
96 union value *
97 text_to_value (const gchar *text,
98                const struct variable *var,
99                union value *val)
100 {
101   return text_to_value__ (text, var_get_print_format (var),
102                           var_get_encoding (var), val);
103 }
104
105 /* Converts TEXT, which contains a value in the given FORMAT encoding in
106    ENCODING, into a value.
107
108    VAL will be initialised and filled by this function.
109    It is the caller's responsibility to destroy VAL when no longer needed.
110
111    On success, VAL is returned, NULL otherwise.
112 */
113 union value *
114 text_to_value__ (const gchar *text,
115                  const struct fmt_spec *format,
116                  const gchar *encoding,
117                  union value *val)
118 {
119   int width = fmt_var_width (format);
120
121   if (format->type != FMT_A)
122     {
123       if (! text) return NULL;
124
125       {
126         const gchar *s = text;
127         while (*s)
128           {
129             if (!isspace (*s))
130               break;
131             s++;
132           }
133
134         if (!*s) return NULL;
135       }
136     }
137
138   value_init (val, width);
139   char *err = data_in (ss_cstr (text), UTF8, format->type,
140                        settings_get_fmt_settings (), val, width, encoding);
141
142   if (err)
143     {
144       value_destroy (val, width);
145       val = NULL;
146       free (err);
147     }
148
149   return val;
150 }
151
152
153 #define _(msgid) gettext (msgid)
154 #define N_(msgid) msgid
155
156 /* Create a deep copy of SRC */
157 GtkListStore *
158 clone_list_store (const GtkListStore *src)
159 {
160   GtkTreeIter src_iter;
161   gboolean ok;
162   gint i;
163   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
164   GType *types = g_malloc (sizeof (*types) *  n_cols);
165
166   GtkListStore *dest;
167
168   for (i = 0 ; i < n_cols; ++i)
169     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
170
171   dest = gtk_list_store_newv (n_cols, types);
172
173   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
174                                            &src_iter);
175        ok;
176        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
177     {
178       GtkTreeIter dest_iter;
179       gtk_list_store_append  (dest, &dest_iter);
180
181       for (i = 0 ; i < n_cols; ++i)
182         {
183           GValue val = {0};
184
185           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
186           gtk_list_store_set_value (dest, &dest_iter, i, &val);
187
188           g_value_unset (&val);
189         }
190     }
191
192   g_free (types);
193
194   return dest;
195 }
196
197
198
199
200 static gboolean
201 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
202 {
203   *addr = NULL;
204
205   return FALSE;
206 }
207
208 char *
209 paste_syntax_to_window (gchar *syntax)
210 {
211   static GtkWidget *the_syntax_pasteboard = NULL;
212
213   GtkTextBuffer *buffer = NULL;
214
215   if (NULL == the_syntax_pasteboard)
216     {
217       the_syntax_pasteboard = psppire_syntax_window_new (NULL);
218       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
219                         &the_syntax_pasteboard);
220     }
221
222   buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);
223
224   gtk_text_buffer_begin_user_action (buffer);
225   gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
226   gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
227   gtk_text_buffer_end_user_action (buffer);
228
229   gtk_widget_show (the_syntax_pasteboard);
230
231   return syntax;
232 }
233
234
235 /* Return the width of an upper case M (in pixels) when rendered onto
236    WIDGET with its current style.  */
237 gdouble
238 width_of_m (GtkWidget *widget)
239 {
240   PangoContext *context = gtk_widget_create_pango_context (widget);
241   PangoLayout *layout = pango_layout_new (context);
242   PangoRectangle rect;
243
244   pango_layout_set_text (layout, "M", 1);
245   pango_layout_get_extents (layout, NULL, &rect);
246
247   g_object_unref (G_OBJECT (layout));
248   g_object_unref (G_OBJECT (context));
249
250   return rect.width / (gdouble) PANGO_SCALE;
251 }
252