Merge commit 'origin/stable'
[pspp-builds.git] / src / ui / gui / psppire.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2009  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 #include <config.h>
18
19 #include <locale.h>
20 #include <assert.h>
21 #include <libintl.h>
22 #include <gsl/gsl_errno.h>
23
24 #include <argp.h>
25 #include <ui/command-line.h>
26 #include "relocatable.h"
27
28 #include "psppire-data-window.h"
29 #include "psppire.h"
30 #include "widgets.h"
31
32 #include <libpspp/getl.h>
33 #include <unistd.h>
34 #include <data/casereader.h>
35 #include <data/datasheet.h>
36 #include <data/file-handle-def.h>
37 #include <data/settings.h>
38 #include <data/file-name.h>
39 #include <data/procedure.h>
40 #include <libpspp/getl.h>
41 #include <language/lexer/lexer.h>
42 #include <libpspp/version.h>
43 #include <output/output.h>
44 #include <output/journal.h>
45 #include <language/syntax-string-source.h>
46
47 #include <gtk/gtk.h>
48 #include "psppire-dict.h"
49 #include "psppire-var-store.h"
50 #include "psppire-data-store.h"
51 #include "helper.h"
52 #include "message-dialog.h"
53 #include <ui/syntax-gen.h>
54
55 #include "psppire-window-register.h"
56 #include "psppire-output-window.h"
57
58 #include <data/sys-file-reader.h>
59 #include <data/por-file-reader.h>
60
61 #include <ui/source-init-opts.h>
62
63 GtkRecentManager *the_recent_mgr = 0;
64 PsppireDataStore *the_data_store = 0;
65 PsppireVarStore *the_var_store = 0;
66
67 static void create_icon_factory (void);
68
69 struct source_stream *the_source_stream ;
70 struct dataset * the_dataset = NULL;
71
72 static GtkWidget *the_data_window;
73
74 static void
75 replace_casereader (struct casereader *s)
76 {
77   psppire_data_store_set_reader (the_data_store, s);
78 }
79
80 #define _(msgid) gettext (msgid)
81 #define N_(msgid) msgid
82
83
84 const char * output_file_name (void);
85
86
87 void
88 initialize (struct command_line_processor *clp, int argc, char **argv)
89 {
90   PsppireDict *dictionary = 0;
91
92   /* gtk_init messes with the locale.
93      So unset the bits we want to control ourselves */
94   setlocale (LC_NUMERIC, "C");
95
96   bindtextdomain (PACKAGE, locale_dir);
97
98
99   preregister_widgets ();
100
101   gsl_set_error_handler_off ();
102   fn_init ();
103   outp_init ();
104   settings_init (&viewer_width, &viewer_length);
105   fh_init ();
106   the_source_stream =
107     create_source_stream (
108                           fn_getenv_default ("STAT_INCLUDE_PATH", include_path)
109                           );
110
111   the_dataset = create_dataset ();
112
113
114   message_dialog_init (the_source_stream);
115
116   dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
117
118   bind_textdomain_codeset (PACKAGE, "UTF-8");
119
120   /* Create the model for the var_sheet */
121   the_var_store = psppire_var_store_new (dictionary);
122
123   the_data_store = psppire_data_store_new (dictionary);
124   replace_casereader (NULL);
125
126   create_icon_factory ();
127
128   {
129     const char *filename = output_file_name ();
130
131     struct string config_string;
132
133     ds_init_empty (&config_string);
134
135     ds_put_format (&config_string,
136                    "gui:ascii:screen:squeeze=on headers=off top-margin=0 "
137                    "bottom-margin=0 paginate=off length=auto width=auto "
138                    "emphasis=none "
139                    "output-file=\"%s\" append=yes", filename);
140
141     outp_configure_driver_line (ds_ss (&config_string));
142
143     unlink (filename);
144
145     ds_destroy (&config_string);
146   }
147
148   journal_enable ();
149   textdomain (PACKAGE);
150
151
152   the_recent_mgr = gtk_recent_manager_get_default ();
153
154   the_data_window = psppire_data_window_new ();
155
156   command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream);
157   command_line_processor_replace_aux (clp, &non_option_argp, the_source_stream);
158
159   command_line_processor_parse (clp, argc, argv);
160
161   execute_syntax (create_syntax_string_source (""));
162
163   gtk_widget_show (the_data_window);
164 }
165
166
167 void
168 de_initialize (void)
169 {
170   destroy_source_stream (the_source_stream);
171   message_dialog_done ();
172   settings_done ();
173   outp_done ();
174 }
175
176
177 static void
178 func (gpointer key, gpointer value, gpointer data)
179 {
180   gboolean rv;
181   PsppireWindow *window = PSPPIRE_WINDOW (value);
182
183   g_signal_emit_by_name (window, "delete-event", 0, &rv);
184 }
185
186 void
187 psppire_quit (void)
188 {
189   PsppireWindowRegister *reg = psppire_window_register_new ();
190   psppire_window_register_foreach (reg, func, NULL);
191
192   gtk_main_quit ();
193 }
194
195
196 struct icon_info
197 {
198   const char *file_name;
199   const gchar *id;
200 };
201
202
203 static const struct icon_info icons[] =
204   {
205     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
206     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
207     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
208     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
209     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
210     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
211     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
212     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
213     {PKGDATADIR "/nominal.png",         "var-nominal"},
214     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
215     {PKGDATADIR "/scale.png",           "var-scale"},
216     {PKGDATADIR "/string.png",          "var-string"},
217     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
218   };
219
220 static void
221 create_icon_factory (void)
222 {
223   gint i;
224   GtkIconFactory *factory = gtk_icon_factory_new ();
225
226   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
227     {
228       GError *err = NULL;
229       GdkPixbuf *pixbuf =
230         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
231
232       if ( pixbuf )
233         {
234           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
235           g_object_unref (pixbuf);
236           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
237         }
238       else
239         {
240           g_warning ("Cannot create icon: %s", err->message);
241           g_clear_error (&err);
242         }
243     }
244
245   {
246     /* Create our own "pspp-stock-reset" item, using the
247        GTK_STOCK_REFRESH icon set */
248
249     GtkStockItem items[] = {
250       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
251       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
252     };
253
254
255     gtk_stock_add (items, 2);
256     gtk_icon_factory_add (factory, "pspp-stock-reset",
257                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
258                           );
259
260     gtk_icon_factory_add (factory, "pspp-stock-select",
261                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
262                           );
263   }
264
265   gtk_icon_factory_add_default (factory);
266 }
267
268 \f
269
270 static error_t
271 parse_non_options (int key, char *arg, struct argp_state *state)
272 {
273   struct source_stream *ss = state->input;
274
275   if ( NULL == ss )
276     return 0;
277
278   switch (key)
279     {
280     case ARGP_KEY_ARG:
281       {
282         gchar *filename = NULL;
283         gchar *utf8 = NULL;
284         const gchar *local_encoding = NULL;
285         gsize written = -1;
286         const gboolean local_is_utf8 = g_get_charset (&local_encoding);
287
288         /* There seems to be no Glib function to convert from local encoding
289            to filename encoding.  Therefore it has to be done in two steps:
290            the intermediate encoding is UTF8.
291
292            Either step could fail.  However, in many cases the file can still
293            be loaded even if the conversion fails. So in those cases, after showing
294            a warning, we simply copy the locally encoded filename to the destination
295            and hope for the best.
296         */
297
298         if ( local_is_utf8)
299           {
300             utf8 = strdup (arg);
301           }
302         else
303           {
304             GError *err = NULL;
305             utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
306             if ( NULL == utf8)
307               {
308                 g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
309                            local_encoding,
310                            err->message);
311                 g_clear_error (&err);
312               }
313           }
314
315         if ( NULL != utf8)
316           {
317             GError *err = NULL;
318             filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
319             if ( NULL == filename)
320               {
321                 g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
322                            err->message);
323                 g_clear_error (&err);
324               }
325           }
326
327         g_free (utf8);
328
329         if ( filename == NULL)
330           filename = strdup (arg);
331
332         psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
333
334         g_free (filename);
335         break;
336       }
337     default:
338       return ARGP_ERR_UNKNOWN;
339     }
340   return 0;
341 }
342
343
344 const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};
345
346
347 const char *
348 output_file_name (void)
349 {
350   const char *dir = default_output_path ();
351   static char *filename = NULL;
352
353   if ( NULL == filename )
354     filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME);
355
356   return filename;
357 }