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