4e9cdfb418187f2454ef3434513e0f4f2b01b440
[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   int row = 0;
167   GtkListStore *dest;
168
169   for (i = 0 ; i < n_cols; ++i)
170     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
171
172   dest = gtk_list_store_newv (n_cols, types);
173
174   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
175                                            &src_iter);
176        ok;
177        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
178     {
179       GtkTreeIter dest_iter;
180       gtk_list_store_append  (dest, &dest_iter);
181
182       for (i = 0 ; i < n_cols; ++i)
183         {
184           GValue val = {0};
185
186           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
187           gtk_list_store_set_value (dest, &dest_iter, i, &val);
188
189           g_value_unset (&val);
190         }
191       row++;
192     }
193
194   g_free (types);
195
196   return dest;
197 }
198
199
200
201
202 static gboolean
203 on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
204 {
205   *addr = NULL;
206
207   return FALSE;
208 }
209
210 char *
211 paste_syntax_to_window (gchar *syntax)
212 {
213   static GtkWidget *the_syntax_pasteboard = NULL;
214
215   GtkTextBuffer *buffer = NULL;
216
217   if (NULL == the_syntax_pasteboard)
218     {
219       the_syntax_pasteboard = psppire_syntax_window_new (NULL);
220       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
221                         &the_syntax_pasteboard);
222     }
223
224   buffer = GTK_TEXT_BUFFER (PSPPIRE_SYNTAX_WINDOW (the_syntax_pasteboard)->buffer);
225
226   gtk_text_buffer_begin_user_action (buffer);
227   gtk_text_buffer_insert_at_cursor (buffer, syntax, -1);
228   gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
229   gtk_text_buffer_end_user_action (buffer);
230
231   gtk_widget_show (the_syntax_pasteboard);
232
233   return syntax;
234 }
235
236
237 /* Return the width of an upper case M (in pixels) when rendered onto
238    WIDGET with its current style.  */
239 gdouble
240 width_of_m (GtkWidget *widget)
241 {
242   PangoContext *context = gtk_widget_create_pango_context (widget);
243   PangoLayout *layout = pango_layout_new (context);
244   PangoRectangle rect;
245
246   pango_layout_set_text (layout, "M", 1);
247   pango_layout_get_extents (layout, NULL, &rect);
248
249   g_object_unref (G_OBJECT (layout));
250   g_object_unref (G_OBJECT (context));
251
252   return rect.width / (gdouble) PANGO_SCALE;
253 }
254