Remove last vestiges of libglade dependencies
[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 ( !w )
147     g_critical ("Widget \"%s\" could not be found\n", name);
148
149   return w;
150 }
151
152 /* Converts a string in the pspp locale to utf-8.
153    The return value must be freed when no longer required*/
154 gchar *
155 pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err)
156 {
157   return recode_string (CONV_PSPP_TO_UTF8, text, len);
158 }
159
160 #define _(msgid) gettext (msgid)
161 #define N_(msgid) msgid
162
163
164 static void
165 give_help (void)
166 {
167   GtkWidget *dialog;
168
169   dialog = gtk_message_dialog_new (NULL,
170                                    GTK_DIALOG_MODAL,
171                                    GTK_MESSAGE_INFO,
172                                    GTK_BUTTONS_CLOSE,
173                                    _("Sorry. The help system hasn't yet "
174                                      "been implemented."));
175   gtk_dialog_run (GTK_DIALOG (dialog));
176   gtk_widget_destroy (dialog);
177 }
178
179 void
180 connect_help (GtkBuilder *xml)
181 {
182   GSList *helps = gtk_builder_get_objects (xml);
183
184   GSList *i;
185   for ( i = helps; i ; i = g_slist_next (i))
186     {
187       GObject *o = i->data;
188       if ( GTK_IS_WIDGET (o) )
189         {
190           gchar *name = NULL;
191           gchar s[12] = {0};
192           g_object_get (o, "name", &name, NULL);
193
194           if ( name)
195             strncpy (s, name, 11);
196           s[11] = '\0';
197
198
199           if ( 0 == strcmp ("help_button", s))
200             {
201             g_signal_connect (GTK_WIDGET (o), "clicked", give_help, 0);
202             }
203         }
204     }
205
206   g_slist_free (helps);
207 }
208
209
210 void
211 reference_manual (GtkMenuItem *menu, gpointer data)
212 {
213   GError *err = NULL;
214   if ( ! g_spawn_command_line_async ("yelp info:pspp", &err) )
215     {
216       msg (ME, _("Cannot open reference manual: %s"), err->message);
217     }
218   g_clear_error (&err);
219 }
220
221
222 extern struct dataset *the_dataset;
223 extern struct source_stream *the_source_stream;
224 extern PsppireDataStore *the_data_store;
225
226 /* Lazy casereader callback function used by execute_syntax. */
227 static struct casereader *
228 create_casereader_from_data_store (void *data_store_)
229 {
230   PsppireDataStore *data_store = data_store_;
231   return psppire_data_store_get_reader (data_store);
232 }
233
234 gboolean
235 execute_syntax (struct getl_interface *sss)
236 {
237   struct lexer *lexer;
238   gboolean retval = TRUE;
239
240   struct casereader *reader;
241   size_t value_cnt;
242   casenumber case_cnt;
243   unsigned long int lazy_serial;
244
245   /* When the user executes a number of snippets of syntax in a
246      row, none of which read from the active file, the GUI becomes
247      progressively less responsive.  The reason is that each syntax
248      execution encapsulates the active file data in another
249      datasheet layer.  The cumulative effect of having a number of
250      layers of datasheets wastes time and space.
251
252      To solve the problem, we use a "lazy casereader", a wrapper
253      around the casereader obtained from the data store, that
254      only actually instantiates that casereader when it is
255      needed.  If the data store casereader is never needed, then
256      it is reused the next time syntax is run, without wrapping
257      it in another layer. */
258   value_cnt = psppire_data_store_get_value_count (the_data_store);
259   case_cnt = psppire_data_store_get_case_count (the_data_store);
260   reader = lazy_casereader_create (value_cnt, case_cnt,
261                                    create_casereader_from_data_store,
262                                    the_data_store, &lazy_serial);
263   proc_set_active_file_data (the_dataset, reader);
264
265   g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
266
267   lexer = lex_create (the_source_stream);
268
269   getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
270
271   for (;;)
272     {
273       enum cmd_result result = cmd_parse (lexer, the_dataset);
274
275       if ( cmd_result_is_failure (result))
276         {
277           retval = FALSE;
278           if ( source_stream_current_error_mode (the_source_stream)
279                == ERRMODE_STOP )
280             break;
281         }
282
283       if ( result == CMD_EOF || result == CMD_FINISH)
284         break;
285     }
286
287   getl_abort_noninteractive (the_source_stream);
288
289   lex_destroy (lexer);
290
291   psppire_dict_replace_dictionary (the_data_store->dict,
292                                    dataset_dict (the_dataset));
293
294   reader = proc_extract_active_file_data (the_dataset);
295   if (!lazy_casereader_destroy (reader, lazy_serial))
296     psppire_data_store_set_reader (the_data_store, reader);
297
298   som_flush ();
299
300   psppire_output_window_reload ();
301
302   return retval;
303 }
304
305
306
307 /* Create a deep copy of SRC */
308 GtkListStore *
309 clone_list_store (const GtkListStore *src)
310 {
311   GtkTreeIter src_iter;
312   gboolean ok;
313   gint i;
314   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
315   GType *types = g_malloc (sizeof (*types) *  n_cols);
316
317   int row = 0;
318   GtkListStore *dest;
319
320   for (i = 0 ; i < n_cols; ++i )
321     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
322
323   dest = gtk_list_store_newv (n_cols, types);
324
325   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
326                                            &src_iter);
327        ok;
328        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
329     {
330       GtkTreeIter dest_iter;
331       gtk_list_store_append  (dest, &dest_iter);
332
333       for (i = 0 ; i < n_cols; ++i )
334         {
335           GValue val = {0};
336
337           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
338           gtk_list_store_set_value (dest, &dest_iter, i, &val);
339
340           g_value_unset (&val);
341         }
342       row++;
343     }
344
345   g_free (types);
346
347   return dest;
348 }
349
350
351 void
352 paste_syntax_in_new_window (const gchar *syntax)
353 {
354   GtkWidget *se = psppire_syntax_window_new ();
355
356   gtk_text_buffer_insert_at_cursor (PSPPIRE_SYNTAX_WINDOW (se)->buffer, syntax, -1);
357
358   gtk_widget_show (se);
359 }