Convert manual to docbook and load that in yelp.
[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, GType type)
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   if ( ! g_type_is_a (G_OBJECT_TYPE (o), type))
134    {
135      g_critical ("Object \"%s\" was expected to have type %s, but in fact has type %s", 
136         name, g_type_name (type), G_OBJECT_TYPE_NAME (o));
137    }
138
139   return o;
140 }
141
142
143 GtkAction *
144 get_action_assert (GtkBuilder *builder, const gchar *name)
145 {
146   return GTK_ACTION (get_object_assert (builder, name, GTK_TYPE_ACTION));
147 }
148
149 GtkWidget *
150 get_widget_assert (GtkBuilder *builder, const gchar *name)
151 {
152   return GTK_WIDGET (get_object_assert (builder, name, GTK_TYPE_WIDGET));
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 (GtkBuilder *xml)
184 {
185   GSList *helps = gtk_builder_get_objects (xml);
186
187   GSList *i;
188   for ( i = helps; i ; i = g_slist_next (i))
189     {
190       GObject *o = i->data;
191       if ( GTK_IS_WIDGET (o) )
192         {
193           gchar *name = NULL;
194           gchar s[12] = {0};
195           g_object_get (o, "name", &name, NULL);
196
197           if ( name)
198             strncpy (s, name, 11);
199           s[11] = '\0';
200
201
202           if ( 0 == strcmp ("help_button", s))
203             {
204             g_signal_connect (o, "clicked", give_help, 0);
205             }
206         }
207     }
208
209   g_slist_free (helps);
210 }
211
212
213 void
214 reference_manual (GtkMenuItem *menu, gpointer data)
215 {
216   GError *err = NULL;
217   gchar *cmd = g_strdup_printf ("yelp file://%s", relocate (DOCDIR "/pspp.xml"));
218
219   if ( ! g_spawn_command_line_async (cmd, &err) )
220     {
221       msg (ME, _("Cannot open reference manual: %s"), err->message);
222     }
223
224   g_free (cmd);
225   g_clear_error (&err);
226 }
227
228
229 extern struct dataset *the_dataset;
230 extern struct source_stream *the_source_stream;
231 extern PsppireDataStore *the_data_store;
232
233 /* Lazy casereader callback function used by execute_syntax. */
234 static struct casereader *
235 create_casereader_from_data_store (void *data_store_)
236 {
237   PsppireDataStore *data_store = data_store_;
238   return psppire_data_store_get_reader (data_store);
239 }
240
241 gboolean
242 execute_syntax (struct getl_interface *sss)
243 {
244   struct lexer *lexer;
245   gboolean retval = TRUE;
246
247   struct casereader *reader;
248   size_t value_cnt;
249   casenumber case_cnt;
250   unsigned long int lazy_serial;
251
252   /* When the user executes a number of snippets of syntax in a
253      row, none of which read from the active file, the GUI becomes
254      progressively less responsive.  The reason is that each syntax
255      execution encapsulates the active file data in another
256      datasheet layer.  The cumulative effect of having a number of
257      layers of datasheets wastes time and space.
258
259      To solve the problem, we use a "lazy casereader", a wrapper
260      around the casereader obtained from the data store, that
261      only actually instantiates that casereader when it is
262      needed.  If the data store casereader is never needed, then
263      it is reused the next time syntax is run, without wrapping
264      it in another layer. */
265   value_cnt = psppire_data_store_get_value_count (the_data_store);
266   case_cnt = psppire_data_store_get_case_count (the_data_store);
267   reader = lazy_casereader_create (value_cnt, case_cnt,
268                                    create_casereader_from_data_store,
269                                    the_data_store, &lazy_serial);
270   proc_set_active_file_data (the_dataset, reader);
271
272   g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
273
274   lexer = lex_create (the_source_stream);
275
276   getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
277
278   for (;;)
279     {
280       enum cmd_result result = cmd_parse (lexer, the_dataset);
281
282       if ( cmd_result_is_failure (result))
283         {
284           retval = FALSE;
285           if ( source_stream_current_error_mode (the_source_stream)
286                == ERRMODE_STOP )
287             break;
288         }
289
290       if ( result == CMD_EOF || result == CMD_FINISH)
291         break;
292     }
293
294   getl_abort_noninteractive (the_source_stream);
295
296   lex_destroy (lexer);
297
298   psppire_dict_replace_dictionary (the_data_store->dict,
299                                    dataset_dict (the_dataset));
300
301   reader = proc_extract_active_file_data (the_dataset);
302   if (!lazy_casereader_destroy (reader, lazy_serial))
303     psppire_data_store_set_reader (the_data_store, reader);
304
305   som_flush ();
306
307   psppire_output_window_reload ();
308
309   return retval;
310 }
311
312
313
314 /* Create a deep copy of SRC */
315 GtkListStore *
316 clone_list_store (const GtkListStore *src)
317 {
318   GtkTreeIter src_iter;
319   gboolean ok;
320   gint i;
321   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
322   GType *types = g_malloc (sizeof (*types) *  n_cols);
323
324   int row = 0;
325   GtkListStore *dest;
326
327   for (i = 0 ; i < n_cols; ++i )
328     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
329
330   dest = gtk_list_store_newv (n_cols, types);
331
332   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
333                                            &src_iter);
334        ok;
335        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
336     {
337       GtkTreeIter dest_iter;
338       gtk_list_store_append  (dest, &dest_iter);
339
340       for (i = 0 ; i < n_cols; ++i )
341         {
342           GValue val = {0};
343
344           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
345           gtk_list_store_set_value (dest, &dest_iter, i, &val);
346
347           g_value_unset (&val);
348         }
349       row++;
350     }
351
352   g_free (types);
353
354   return dest;
355 }
356
357
358 void
359 paste_syntax_in_new_window (const gchar *syntax)
360 {
361   GtkWidget *se = psppire_syntax_window_new ();
362
363   gtk_text_buffer_insert_at_cursor (PSPPIRE_SYNTAX_WINDOW (se)->buffer, syntax, -1);
364
365   gtk_widget_show (se);
366 }