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