Consolidate multiple messages into single message dialog. Patch
[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,
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
154
155
156 void
157 reference_manual (GtkMenuItem *menu, gpointer data)
158 {
159   GError *err = NULL;
160   if ( ! g_spawn_command_line_async ("yelp info:pspp", &err) )
161     {
162       msg (ME, _("Cannot open reference manual: %s"), err->message);
163     }
164   g_clear_error (&err);
165 }
166
167
168 extern struct dataset *the_dataset;
169 extern struct source_stream *the_source_stream;
170 extern PsppireDataStore *the_data_store;
171
172 /* Lazy casereader callback function used by execute_syntax. */
173 static struct casereader *
174 create_casereader_from_data_store (void *data_store_)
175 {
176   PsppireDataStore *data_store = data_store_;
177   return psppire_data_store_get_reader (data_store);
178 }
179
180 gboolean
181 execute_syntax (struct getl_interface *sss)
182 {
183   struct lexer *lexer;
184   gboolean retval = TRUE;
185
186   struct casereader *reader;
187   size_t value_cnt;
188   casenumber case_cnt;
189   unsigned long int lazy_serial;
190
191   /* When the user executes a number of snippets of syntax in a
192      row, none of which read from the active file, the GUI becomes
193      progressively less responsive.  The reason is that each syntax
194      execution encapsulates the active file data in another
195      datasheet layer.  The cumulative effect of having a number of
196      layers of datasheets wastes time and space.
197
198      To solve the problem, we use a "lazy casereader", a wrapper
199      around the casereader obtained from the data store, that
200      only actually instantiates that casereader when it is
201      needed.  If the data store casereader is never needed, then
202      it is reused the next time syntax is run, without wrapping
203      it in another layer. */
204   value_cnt = psppire_data_store_get_value_count (the_data_store);
205   case_cnt = psppire_data_store_get_case_count (the_data_store);
206   reader = lazy_casereader_create (value_cnt, case_cnt,
207                                    create_casereader_from_data_store,
208                                    the_data_store, &lazy_serial);
209   proc_set_active_file_data (the_dataset, reader);
210
211   g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
212
213   lexer = lex_create (the_source_stream);
214
215   getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
216
217   for (;;)
218     {
219       enum cmd_result result = cmd_parse (lexer, the_dataset);
220
221       if ( cmd_result_is_failure (result))
222         {
223           retval = FALSE;
224           if ( source_stream_current_error_mode (the_source_stream)
225                == ERRMODE_STOP )
226             break;
227         }
228
229       if ( result == CMD_EOF || result == CMD_FINISH)
230         break;
231     }
232
233   getl_abort_noninteractive (the_source_stream);
234
235   lex_destroy (lexer);
236
237   psppire_dict_replace_dictionary (the_data_store->dict,
238                                    dataset_dict (the_dataset));
239
240   reader = proc_extract_active_file_data (the_dataset);
241   if (!lazy_casereader_destroy (reader, lazy_serial))
242     psppire_data_store_set_case_file (the_data_store,
243                                       psppire_case_file_new (reader));
244
245   som_flush ();
246
247   reload_the_viewer ();
248
249   return retval;
250 }
251
252
253
254 #ifdef G_ENABLE_DEBUG
255 # define g_marshal_value_peek_int(v)      g_value_get_int (v)
256 #else
257 # define g_marshal_value_peek_int(v)      (v)->data[0].v_int
258 #endif
259
260
261 /* VOID:INT,INT,INT */
262 void
263 marshaller_VOID__INT_INT_INT (GClosure     *closure,
264                         GValue       *return_value,
265                         guint         n_param_values,
266                         const GValue *param_values,
267                         gpointer      invocation_hint,
268                         gpointer      marshal_data)
269 {
270   typedef void (*GMarshalFunc_VOID__INT_INT_INT) (gpointer     data1,
271                                                   gint         arg_1,
272                                                   gint         arg_2,
273                                                   gint         arg_3,
274                                                   gpointer     data2);
275   register GMarshalFunc_VOID__INT_INT_INT callback;
276   register GCClosure *cc = (GCClosure*) closure;
277   register gpointer data1, data2;
278
279   g_return_if_fail (n_param_values == 4);
280
281   if (G_CCLOSURE_SWAP_DATA (closure))
282     {
283       data1 = closure->data;
284       data2 = g_value_peek_pointer (param_values + 0);
285     }
286   else
287     {
288       data1 = g_value_peek_pointer (param_values + 0);
289       data2 = closure->data;
290     }
291   callback = (GMarshalFunc_VOID__INT_INT_INT) (marshal_data ? marshal_data : cc->callback);
292
293   callback (data1,
294             g_marshal_value_peek_int (param_values + 1),
295             g_marshal_value_peek_int (param_values + 2),
296             g_marshal_value_peek_int (param_values + 3),
297             data2);
298 }
299
300 /* Create a deep copy of SRC */
301 GtkListStore *
302 clone_list_store (const GtkListStore *src)
303 {
304   GtkTreeIter src_iter;
305   gboolean ok;
306   gint i;
307   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
308   GType *types = g_malloc (sizeof (*types) *  n_cols);
309
310   int row = 0;
311   GtkListStore *dest;
312
313   for (i = 0 ; i < n_cols; ++i )
314     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
315
316   dest = gtk_list_store_newv (n_cols, types);
317
318   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
319                                            &src_iter);
320        ok;
321        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
322     {
323       GtkTreeIter dest_iter;
324       gtk_list_store_append  (dest, &dest_iter);
325
326       for (i = 0 ; i < n_cols; ++i )
327         {
328           GValue val = {0};
329
330           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
331           gtk_list_store_set_value (dest, &dest_iter, i, &val);
332
333           g_value_unset (&val);
334         }
335       row++;
336     }
337
338   g_free (types);
339
340   return dest;
341 }
342
343