include format.h only where necessary.
[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 #ifdef G_ENABLE_DEBUG
258 # define g_marshal_value_peek_int(v)      g_value_get_int (v)
259 #else
260 # define g_marshal_value_peek_int(v)      (v)->data[0].v_int
261 #endif
262
263
264 /* VOID:INT,INT,INT */
265 void
266 marshaller_VOID__INT_INT_INT (GClosure     *closure,
267                         GValue       *return_value,
268                         guint         n_param_values,
269                         const GValue *param_values,
270                         gpointer      invocation_hint,
271                         gpointer      marshal_data)
272 {
273   typedef void (*GMarshalFunc_VOID__INT_INT_INT) (gpointer     data1,
274                                                   gint         arg_1,
275                                                   gint         arg_2,
276                                                   gint         arg_3,
277                                                   gpointer     data2);
278   register GMarshalFunc_VOID__INT_INT_INT callback;
279   register GCClosure *cc = (GCClosure*) closure;
280   register gpointer data1, data2;
281
282   g_return_if_fail (n_param_values == 4);
283
284   if (G_CCLOSURE_SWAP_DATA (closure))
285     {
286       data1 = closure->data;
287       data2 = g_value_peek_pointer (param_values + 0);
288     }
289   else
290     {
291       data1 = g_value_peek_pointer (param_values + 0);
292       data2 = closure->data;
293     }
294   callback = (GMarshalFunc_VOID__INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
295
296   callback (data1,
297             g_marshal_value_peek_int (param_values + 1),
298             g_marshal_value_peek_int (param_values + 2),
299             g_marshal_value_peek_int (param_values + 3),
300             data2);
301 }
302
303 /* Create a deep copy of SRC */
304 GtkListStore *
305 clone_list_store (const GtkListStore *src)
306 {
307   GtkTreeIter src_iter;
308   gboolean ok;
309   gint i;
310   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
311   GType *types = g_malloc (sizeof (*types) *  n_cols);
312
313   int row = 0;
314   GtkListStore *dest;
315
316   for (i = 0 ; i < n_cols; ++i )
317     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
318
319   dest = gtk_list_store_newv (n_cols, types);
320
321   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
322                                            &src_iter);
323        ok;
324        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
325     {
326       GtkTreeIter dest_iter;
327       gtk_list_store_append  (dest, &dest_iter);
328
329       for (i = 0 ; i < n_cols; ++i )
330         {
331           GValue val = {0};
332
333           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
334           gtk_list_store_set_value (dest, &dest_iter, i, &val);
335
336           g_value_unset (&val);
337         }
338       row++;
339     }
340
341   g_free (types);
342
343   return dest;
344 }
345
346