Re enable the connect_help function
[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 static void
183 connect_help_builder (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 (GTK_WIDGET (o), "clicked", give_help, 0);
205             }
206         }
207     }
208
209   g_slist_free (helps);
210 }
211
212 static void
213 connect_help_glade (GladeXML *xml)
214 {
215   GList *helps = glade_xml_get_widget_prefix (xml, "help_button_");
216
217   GList *i;
218   for ( i = g_list_first (helps); i ; i = g_list_next (i))
219     g_signal_connect (GTK_WIDGET (i->data), "clicked", give_help, 0);
220
221   g_list_free (helps);
222 }
223
224
225 void
226 connect_help (gpointer *xml)
227 {
228   if (GTK_IS_BUILDER (xml))
229     connect_help_builder (GTK_BUILDER (xml));
230
231   else if (GLADE_IS_XML (xml))
232     connect_help_glade (GLADE_XML (xml));
233
234   else
235     {
236       g_error ("XML of type %s", G_OBJECT_TYPE_NAME (xml));
237     }
238 }
239
240
241
242 void
243 reference_manual (GtkMenuItem *menu, gpointer data)
244 {
245   GError *err = NULL;
246   if ( ! g_spawn_command_line_async ("yelp info:pspp", &err) )
247     {
248       msg (ME, _("Cannot open reference manual: %s"), err->message);
249     }
250   g_clear_error (&err);
251 }
252
253
254 extern struct dataset *the_dataset;
255 extern struct source_stream *the_source_stream;
256 extern PsppireDataStore *the_data_store;
257
258 /* Lazy casereader callback function used by execute_syntax. */
259 static struct casereader *
260 create_casereader_from_data_store (void *data_store_)
261 {
262   PsppireDataStore *data_store = data_store_;
263   return psppire_data_store_get_reader (data_store);
264 }
265
266 gboolean
267 execute_syntax (struct getl_interface *sss)
268 {
269   struct lexer *lexer;
270   gboolean retval = TRUE;
271
272   struct casereader *reader;
273   size_t value_cnt;
274   casenumber case_cnt;
275   unsigned long int lazy_serial;
276
277   /* When the user executes a number of snippets of syntax in a
278      row, none of which read from the active file, the GUI becomes
279      progressively less responsive.  The reason is that each syntax
280      execution encapsulates the active file data in another
281      datasheet layer.  The cumulative effect of having a number of
282      layers of datasheets wastes time and space.
283
284      To solve the problem, we use a "lazy casereader", a wrapper
285      around the casereader obtained from the data store, that
286      only actually instantiates that casereader when it is
287      needed.  If the data store casereader is never needed, then
288      it is reused the next time syntax is run, without wrapping
289      it in another layer. */
290   value_cnt = psppire_data_store_get_value_count (the_data_store);
291   case_cnt = psppire_data_store_get_case_count (the_data_store);
292   reader = lazy_casereader_create (value_cnt, case_cnt,
293                                    create_casereader_from_data_store,
294                                    the_data_store, &lazy_serial);
295   proc_set_active_file_data (the_dataset, reader);
296
297   g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
298
299   lexer = lex_create (the_source_stream);
300
301   getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
302
303   for (;;)
304     {
305       enum cmd_result result = cmd_parse (lexer, the_dataset);
306
307       if ( cmd_result_is_failure (result))
308         {
309           retval = FALSE;
310           if ( source_stream_current_error_mode (the_source_stream)
311                == ERRMODE_STOP )
312             break;
313         }
314
315       if ( result == CMD_EOF || result == CMD_FINISH)
316         break;
317     }
318
319   getl_abort_noninteractive (the_source_stream);
320
321   lex_destroy (lexer);
322
323   psppire_dict_replace_dictionary (the_data_store->dict,
324                                    dataset_dict (the_dataset));
325
326   reader = proc_extract_active_file_data (the_dataset);
327   if (!lazy_casereader_destroy (reader, lazy_serial))
328     psppire_data_store_set_reader (the_data_store, reader);
329
330   som_flush ();
331
332   psppire_output_window_reload ();
333
334   return retval;
335 }
336
337
338
339 /* Create a deep copy of SRC */
340 GtkListStore *
341 clone_list_store (const GtkListStore *src)
342 {
343   GtkTreeIter src_iter;
344   gboolean ok;
345   gint i;
346   const gint n_cols =  gtk_tree_model_get_n_columns (GTK_TREE_MODEL (src));
347   GType *types = g_malloc (sizeof (*types) *  n_cols);
348
349   int row = 0;
350   GtkListStore *dest;
351
352   for (i = 0 ; i < n_cols; ++i )
353     types[i] = gtk_tree_model_get_column_type (GTK_TREE_MODEL (src), i);
354
355   dest = gtk_list_store_newv (n_cols, types);
356
357   for (ok = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (src),
358                                            &src_iter);
359        ok;
360        ok = gtk_tree_model_iter_next (GTK_TREE_MODEL (src), &src_iter))
361     {
362       GtkTreeIter dest_iter;
363       gtk_list_store_append  (dest, &dest_iter);
364
365       for (i = 0 ; i < n_cols; ++i )
366         {
367           GValue val = {0};
368
369           gtk_tree_model_get_value (GTK_TREE_MODEL (src), &src_iter, i, &val);
370           gtk_list_store_set_value (dest, &dest_iter, i, &val);
371
372           g_value_unset (&val);
373         }
374       row++;
375     }
376
377   g_free (types);
378
379   return dest;
380 }
381
382
383 void
384 paste_syntax_in_new_window (const gchar *syntax)
385 {
386   GtkWidget *se = psppire_syntax_window_new ();
387
388   gtk_text_buffer_insert_at_cursor (PSPPIRE_SYNTAX_WINDOW (se)->buffer, syntax, -1);
389
390   gtk_widget_show (se);
391 }