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