Merge master into output branch.
[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   psppire_output_window_setup ();
125
126   journal_enable ();
127   textdomain (PACKAGE);
128
129
130   the_recent_mgr = gtk_recent_manager_get_default ();
131
132   the_data_window = psppire_data_window_new ();
133
134   command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream);
135   command_line_processor_replace_aux (clp, &non_option_argp, the_source_stream);
136
137   command_line_processor_parse (clp, argc, argv);
138
139   execute_syntax (create_syntax_string_source (""));
140
141   gtk_widget_show (the_data_window);
142 }
143
144
145 void
146 de_initialize (void)
147 {
148   destroy_source_stream (the_source_stream);
149   message_dialog_done ();
150   settings_done ();
151   outp_done ();
152   i18n_done ();
153 }
154
155
156 static void
157 func (gpointer key, gpointer value, gpointer data)
158 {
159   gboolean rv;
160   PsppireWindow *window = PSPPIRE_WINDOW (value);
161
162   g_signal_emit_by_name (window, "delete-event", 0, &rv);
163 }
164
165 void
166 psppire_quit (void)
167 {
168   PsppireWindowRegister *reg = psppire_window_register_new ();
169   psppire_window_register_foreach (reg, func, NULL);
170
171   gtk_main_quit ();
172 }
173
174
175 struct icon_info
176 {
177   const char *file_name;
178   const gchar *id;
179 };
180
181
182 static const struct icon_info icons[] =
183   {
184     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
185     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
186     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
187     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
188     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
189     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
190     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
191     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
192     {PKGDATADIR "/nominal.png",         "var-nominal"},
193     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
194     {PKGDATADIR "/scale.png",           "var-scale"},
195     {PKGDATADIR "/string.png",          "var-string"},
196     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
197   };
198
199 static void
200 create_icon_factory (void)
201 {
202   gint i;
203   GtkIconFactory *factory = gtk_icon_factory_new ();
204
205   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
206     {
207       GError *err = NULL;
208       GdkPixbuf *pixbuf =
209         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
210
211       if ( pixbuf )
212         {
213           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
214           g_object_unref (pixbuf);
215           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
216         }
217       else
218         {
219           g_warning ("Cannot create icon: %s", err->message);
220           g_clear_error (&err);
221         }
222     }
223
224   {
225     /* Create our own "pspp-stock-reset" item, using the
226        GTK_STOCK_REFRESH icon set */
227
228     GtkStockItem items[] = {
229       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
230       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
231     };
232
233
234     gtk_stock_add (items, 2);
235     gtk_icon_factory_add (factory, "pspp-stock-reset",
236                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
237                           );
238
239     gtk_icon_factory_add (factory, "pspp-stock-select",
240                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
241                           );
242   }
243
244   gtk_icon_factory_add_default (factory);
245 }
246
247 \f
248
249 static error_t
250 parse_non_options (int key, char *arg, struct argp_state *state)
251 {
252   struct source_stream *ss = state->input;
253
254   if ( NULL == ss )
255     return 0;
256
257   switch (key)
258     {
259     case ARGP_KEY_ARG:
260       {
261         gchar *filename = NULL;
262         gchar *utf8 = NULL;
263         const gchar *local_encoding = NULL;
264         gsize written = -1;
265         const gboolean local_is_utf8 = g_get_charset (&local_encoding);
266
267         /* There seems to be no Glib function to convert from local encoding
268            to filename encoding.  Therefore it has to be done in two steps:
269            the intermediate encoding is UTF8.
270
271            Either step could fail.  However, in many cases the file can still
272            be loaded even if the conversion fails. So in those cases, after showing
273            a warning, we simply copy the locally encoded filename to the destination
274            and hope for the best.
275         */
276
277         if ( local_is_utf8)
278           {
279             utf8 = xstrdup (arg);
280           }
281         else
282           {
283             GError *err = NULL;
284             utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
285             if ( NULL == utf8)
286               {
287                 g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
288                            local_encoding,
289                            err->message);
290                 g_clear_error (&err);
291               }
292           }
293
294         if ( NULL != utf8)
295           {
296             GError *err = NULL;
297             filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
298             if ( NULL == filename)
299               {
300                 g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
301                            err->message);
302                 g_clear_error (&err);
303               }
304           }
305
306         g_free (utf8);
307
308         if ( filename == NULL)
309           filename = xstrdup (arg);
310
311         psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
312
313         g_free (filename);
314         break;
315       }
316     default:
317       return ARGP_ERR_UNKNOWN;
318     }
319   return 0;
320 }
321
322
323 const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};