Remove marshaller from helper.c and use a generated one instead
[pspp-builds.git] / src / ui / gui / helper.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007  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 "message-dialog.h"
28 #include <data/format.h>
29 #include <data/data-in.h>
30 #include <data/data-out.h>
31 #include <data/dictionary.h>
32 #include <data/casereader-provider.h>
33 #include <libpspp/message.h>
34
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 <language/command.h>
43 #include <data/lazy-casereader.h>
44 #include <data/procedure.h>
45 #include <language/lexer/lexer.h>
46 #include "psppire-data-store.h"
47 #include <output/manager.h>
48 #include "output-viewer.h"
49
50 #include "xalloc.h"
51
52 #include <gettext.h>
53
54 /* Formats a value according to FORMAT
55    The returned string must be freed when no longer required */
56 gchar *
57 value_to_text (union value v, struct fmt_spec format)
58 {
59   gchar *s = 0;
60
61   s = g_new (gchar, format.w + 1);
62   data_out (&v, &format, s);
63   s[format.w]='\0';
64   g_strchug (s);
65
66   return s;
67 }
68
69
70
71 gboolean
72 text_to_value (const gchar *text, union value *v,
73               struct fmt_spec format)
74 {
75   bool ok;
76
77   if ( format.type != FMT_A)
78     {
79       if ( ! text ) return FALSE;
80
81       {
82         const gchar *s = text;
83         while (*s)
84           {
85             if ( !isspace (*s))
86               break;
87             s++;
88           }
89
90         if ( !*s) return FALSE;
91       }
92     }
93
94   msg_disable ();
95   ok = data_in (ss_cstr (text), LEGACY_NATIVE, format.type, 0, 0, 0,
96                 v, fmt_var_width (&format));
97   msg_enable ();
98
99   return ok;
100 }
101
102
103 GtkWidget *
104 get_widget_assert (GladeXML *xml, const gchar *name)
105 {
106   GtkWidget *w;
107   g_assert (xml);
108   g_assert (name);
109
110   w = glade_xml_get_widget (xml, name);
111
112   if ( !w )
113     g_critical ("Widget \"%s\" could not be found\n", name);
114
115   return w;
116 }
117
118 /* Converts a string in the pspp locale to utf-8.
119    The return value must be freed when no longer required*/
120 gchar *
121 pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err)
122 {
123   return recode_string (CONV_PSPP_TO_UTF8, text, len);
124 }
125
126 #define _(msgid) gettext (msgid)
127 #define N_(msgid) msgid
128
129
130 static void
131 give_help (void)
132 {
133   GtkWidget *dialog;
134
135   dialog = gtk_message_dialog_new (NULL,
136                                    GTK_DIALOG_MODAL,
137                                    GTK_MESSAGE_INFO,
138                                    GTK_BUTTONS_CLOSE,
139                                    _("Sorry. The help system hasn't yet "
140                                      "been implemented."));
141   gtk_dialog_run (GTK_DIALOG (dialog));
142   gtk_widget_destroy (dialog);
143 }
144
145 void
146 connect_help (GladeXML *xml)
147 {
148   GList *helps = glade_xml_get_widget_prefix (xml, "help_button_");
149
150   GList *i;
151   for ( i = g_list_first (helps); i ; i = g_list_next (i))
152     g_signal_connect (GTK_WIDGET (i->data), "clicked", give_help, 0);
153
154   g_list_free (helps);
155 }
156
157
158
159 void
160 reference_manual (GtkMenuItem *menu, gpointer data)
161 {
162   GError *err = NULL;
163   if ( ! g_spawn_command_line_async ("yelp info:pspp", &err) )
164     {
165       msg (ME, _("Cannot open reference manual: %s"), err->message);
166     }
167   g_clear_error (&err);
168 }
169
170
171 extern struct dataset *the_dataset;
172 extern struct source_stream *the_source_stream;
173 extern PsppireDataStore *the_data_store;
174
175 /* Lazy casereader callback function used by execute_syntax. */
176 static struct casereader *
177 create_casereader_from_data_store (void *data_store_)
178 {
179   PsppireDataStore *data_store = data_store_;
180   return psppire_data_store_get_reader (data_store);
181 }
182
183 gboolean
184 execute_syntax (struct getl_interface *sss)
185 {
186   struct lexer *lexer;
187   gboolean retval = TRUE;
188
189   struct casereader *reader;
190   size_t value_cnt;
191   casenumber case_cnt;
192   unsigned long int lazy_serial;
193
194   /* When the user executes a number of snippets of syntax in a
195      row, none of which read from the active file, the GUI becomes
196      progressively less responsive.  The reason is that each syntax
197      execution encapsulates the active file data in another
198      datasheet layer.  The cumulative effect of having a number of
199      layers of datasheets wastes time and space.
200
201      To solve the problem, we use a "lazy casereader", a wrapper
202      around the casereader obtained from the data store, that
203      only actually instantiates that casereader when it is
204      needed.  If the data store casereader is never needed, then
205      it is reused the next time syntax is run, without wrapping
206      it in another layer. */
207   value_cnt = psppire_data_store_get_value_count (the_data_store);
208   case_cnt = psppire_data_store_get_case_count (the_data_store);
209   reader = lazy_casereader_create (value_cnt, case_cnt,
210                                    create_casereader_from_data_store,
211                                    the_data_store, &lazy_serial);
212   proc_set_active_file_data (the_dataset, reader);
213
214   g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
215
216   lexer = lex_create (the_source_stream);
217
218   getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
219
220   for (;;)
221     {
222       enum cmd_result result = cmd_parse (lexer, the_dataset);
223
224       if ( cmd_result_is_failure (result))
225         {
226           retval = FALSE;
227           if ( source_stream_current_error_mode (the_source_stream)
228                == ERRMODE_STOP )
229             break;
230         }
231
232       if ( result == CMD_EOF || result == CMD_FINISH)
233         break;
234     }
235
236   getl_abort_noninteractive (the_source_stream);
237
238   lex_destroy (lexer);
239
240   psppire_dict_replace_dictionary (the_data_store->dict,
241                                    dataset_dict (the_dataset));
242
243   reader = proc_extract_active_file_data (the_dataset);
244   if (!lazy_casereader_destroy (reader, lazy_serial))
245     psppire_data_store_set_case_file (the_data_store,
246                                       psppire_case_file_new (reader));
247
248   som_flush ();
249
250   reload_the_viewer ();
251
252   return retval;
253 }
254
255
256
257 /* Create a deep copy of SRC */
258 GtkListStore *
259 clone_list_store (const GtkListStore *src)
260 {
261   GtkTreeIter src_iter;
262   gboolean ok;
263   gint i;
264   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
265   GType *types = g_malloc (sizeof (*types) *  n_cols);
266
267   int row = 0;
268   GtkListStore *dest;
269
270   for (i = 0 ; i < n_cols; ++i )
271     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
272
273   dest = gtk_list_store_newv (n_cols, types);
274
275   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
276                                            &src_iter);
277        ok;
278        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
279     {
280       GtkTreeIter dest_iter;
281       gtk_list_store_append  (dest, &dest_iter);
282
283       for (i = 0 ; i < n_cols; ++i )
284         {
285           GValue val = {0};
286
287           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
288           gtk_list_store_set_value (dest, &dest_iter, i, &val);
289
290           g_value_unset (&val);
291         }
292       row++;
293     }
294
295   g_free (types);
296
297   return dest;
298 }
299
300