treewide: Use struct fmt_spec by value instead of pointer in most cases.
[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, struct fmt_spec format, const char *encoding)
74 {
75   gchar *s;
76
77   s = data_out_stretchy (&v, encoding, format, settings_get_fmt_settings (),
78                          NULL);
79   if (fmt_is_numeric (format.type))
80     g_strchug (s);
81   else
82     g_strchomp (s);
83
84   return s;
85 }
86
87 /* Converts TEXT to a value.
88
89    VAL will be initialised and filled by this function.
90    It is the caller's responsibility to destroy VAL when no longer needed.
91    VAR must be the variable with which VAL is associated.
92
93    On success, VAL is returned, NULL otherwise.
94 */
95 union value *
96 text_to_value (const gchar *text,
97                const struct variable *var,
98                union value *val)
99 {
100   return text_to_value__ (text, var_get_print_format (var),
101                           var_get_encoding (var), val);
102 }
103
104 /* Converts TEXT, which contains a value in the given FORMAT encoding in
105    ENCODING, into a value.
106
107    VAL will be initialised and filled by this function.
108    It is the caller's responsibility to destroy VAL when no longer needed.
109
110    On success, VAL is returned, NULL otherwise.
111 */
112 union value *
113 text_to_value__ (const gchar *text,
114                  struct fmt_spec format,
115                  const gchar *encoding,
116                  union value *val)
117 {
118   int width = fmt_var_width (format);
119
120   if (format.type != FMT_A)
121     {
122       if (! text) return NULL;
123
124       {
125         const gchar *s = text;
126         while (*s)
127           {
128             if (!isspace (*s))
129               break;
130             s++;
131           }
132
133         if (!*s) return NULL;
134       }
135     }
136
137   value_init (val, width);
138   char *err = data_in (ss_cstr (text), UTF8, format.type,
139                        settings_get_fmt_settings (), val, width, encoding);
140
141   if (err)
142     {
143       value_destroy (val, width);
144       val = NULL;
145       free (err);
146     }
147
148   return val;
149 }
150
151
152 #define _(msgid) gettext (msgid)
153 #define N_(msgid) msgid
154
155 /* Create a deep copy of SRC */
156 GtkListStore *
157 clone_list_store (const GtkListStore *src)
158 {
159   GtkTreeIter src_iter;
160   gboolean ok;
161   gint i;
162   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
163   GType *types = g_malloc (sizeof (*types) *  n_cols);
164
165   GtkListStore *dest;
166
167   for (i = 0 ; i < n_cols; ++i)
168     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
169
170   dest = gtk_list_store_newv (n_cols, types);
171
172   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
173                                            &src_iter);
174        ok;
175        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
176     {
177       GtkTreeIter dest_iter;
178       gtk_list_store_append  (dest, &dest_iter);
179
180       for (i = 0 ; i < n_cols; ++i)
181         {
182           GValue val = {0};
183
184           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
185           gtk_list_store_set_value (dest, &dest_iter, i, &val);
186
187           g_value_unset (&val);
188         }
189     }
190
191   g_free (types);
192
193   return dest;
194 }
195
196
197
198
199 static gboolean
200 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
201 {
202   *addr = NULL;
203
204   return FALSE;
205 }
206
207 char *
208 paste_syntax_to_window (gchar *syntax)
209 {
210   static GtkWidget *the_syntax_pasteboard = NULL;
211
212   GtkTextBuffer *buffer = NULL;
213
214   if (NULL == the_syntax_pasteboard)
215     {
216       the_syntax_pasteboard = psppire_syntax_window_new (NULL);
217       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
218                         &the_syntax_pasteboard);
219     }
220
221   buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);
222
223   gtk_text_buffer_begin_user_action (buffer);
224   gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
225   gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
226   gtk_text_buffer_end_user_action (buffer);
227
228   gtk_widget_show (the_syntax_pasteboard);
229
230   return syntax;
231 }
232
233
234 /* Return the width of an upper case M (in pixels) when rendered onto
235    WIDGET with its current style.  */
236 gdouble
237 width_of_m (GtkWidget *widget)
238 {
239   PangoContext *context = gtk_widget_create_pango_context (widget);
240   PangoLayout *layout = pango_layout_new (context);
241   PangoRectangle rect;
242
243   pango_layout_set_text (layout, "M", 1);
244   pango_layout_get_extents (layout, NULL, &rect);
245
246   g_object_unref (G_OBJECT (layout));
247   g_object_unref (G_OBJECT (context));
248
249   return rect.width / (gdouble) PANGO_SCALE;
250 }
251