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