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