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