Rewrite PSPP output engine.
[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/driver.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 "dict-display.h"
51 #include "psppire-selector.h"
52 #include "psppire-var-view.h"
53 #include "psppire-var-store.h"
54 #include "psppire-data-store.h"
55 #include "executor.h"
56 #include "message-dialog.h"
57 #include <ui/syntax-gen.h>
58
59 #include "psppire-window-register.h"
60 #include "psppire-output-window.h"
61
62 #include <data/sys-file-reader.h>
63 #include <data/por-file-reader.h>
64
65 #include <ui/source-init-opts.h>
66
67 GtkRecentManager *the_recent_mgr = 0;
68 PsppireDataStore *the_data_store = 0;
69 PsppireVarStore *the_var_store = 0;
70
71 static void create_icon_factory (void);
72
73 struct source_stream *the_source_stream ;
74 struct dataset * the_dataset = NULL;
75
76 static GtkWidget *the_data_window;
77
78 static void
79 replace_casereader (struct casereader *s)
80 {
81   psppire_data_store_set_reader (the_data_store, s);
82 }
83
84 #define _(msgid) gettext (msgid)
85 #define N_(msgid) msgid
86
87
88
89
90 void
91 initialize (struct command_line_processor *clp, int argc, char **argv)
92 {
93   PsppireDict *dictionary = 0;
94
95   i18n_init ();
96
97   preregister_widgets ();
98
99   gsl_set_error_handler_off ();
100   fn_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   psppire_output_window_setup ();
126
127   journal_enable ();
128   textdomain (PACKAGE);
129
130
131   the_recent_mgr = gtk_recent_manager_get_default ();
132
133   psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry);
134   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
135   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
136
137   the_data_window = psppire_data_window_new ();
138
139   command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream);
140   command_line_processor_replace_aux (clp, &non_option_argp, the_source_stream);
141
142   command_line_processor_parse (clp, argc, argv);
143
144   execute_syntax (create_syntax_string_source (""));
145
146   gtk_widget_show (the_data_window);
147 }
148
149
150 void
151 de_initialize (void)
152 {
153   destroy_source_stream (the_source_stream);
154   message_dialog_done ();
155   settings_done ();
156   output_close ();
157   i18n_done ();
158 }
159
160
161 static void
162 func (gpointer key, gpointer value, gpointer data)
163 {
164   gboolean rv;
165   PsppireWindow *window = PSPPIRE_WINDOW (value);
166
167   g_signal_emit_by_name (window, "delete-event", 0, &rv);
168 }
169
170 void
171 psppire_quit (void)
172 {
173   PsppireWindowRegister *reg = psppire_window_register_new ();
174   psppire_window_register_foreach (reg, func, NULL);
175
176   gtk_main_quit ();
177 }
178
179
180 struct icon_info
181 {
182   const char *file_name;
183   const gchar *id;
184 };
185
186
187 static const struct icon_info icons[] =
188   {
189     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
190     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
191     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
192     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
193     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
194     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
195     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
196     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
197     {PKGDATADIR "/nominal.png",         "var-nominal"},
198     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
199     {PKGDATADIR "/scale.png",           "var-scale"},
200     {PKGDATADIR "/string.png",          "var-string"},
201     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
202   };
203
204 static void
205 create_icon_factory (void)
206 {
207   gint i;
208   GtkIconFactory *factory = gtk_icon_factory_new ();
209
210   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
211     {
212       GError *err = NULL;
213       GdkPixbuf *pixbuf =
214         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
215
216       if ( pixbuf )
217         {
218           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
219           g_object_unref (pixbuf);
220           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
221         }
222       else
223         {
224           g_warning ("Cannot create icon: %s", err->message);
225           g_clear_error (&err);
226         }
227     }
228
229   {
230     /* Create our own "pspp-stock-reset" item, using the
231        GTK_STOCK_REFRESH icon set */
232
233     GtkStockItem items[] = {
234       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
235       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
236     };
237
238
239     gtk_stock_add (items, 2);
240     gtk_icon_factory_add (factory, "pspp-stock-reset",
241                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
242                           );
243
244     gtk_icon_factory_add (factory, "pspp-stock-select",
245                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
246                           );
247   }
248
249   gtk_icon_factory_add_default (factory);
250 }
251
252 \f
253
254 static error_t
255 parse_non_options (int key, char *arg, struct argp_state *state)
256 {
257   struct source_stream *ss = state->input;
258
259   if ( NULL == ss )
260     return 0;
261
262   switch (key)
263     {
264     case ARGP_KEY_ARG:
265       {
266         gchar *filename = NULL;
267         gchar *utf8 = NULL;
268         const gchar *local_encoding = NULL;
269         gsize written = -1;
270         const gboolean local_is_utf8 = g_get_charset (&local_encoding);
271
272         /* There seems to be no Glib function to convert from local encoding
273            to filename encoding.  Therefore it has to be done in two steps:
274            the intermediate encoding is UTF8.
275
276            Either step could fail.  However, in many cases the file can still
277            be loaded even if the conversion fails. So in those cases, after showing
278            a warning, we simply copy the locally encoded filename to the destination
279            and hope for the best.
280         */
281
282         if ( local_is_utf8)
283           {
284             utf8 = xstrdup (arg);
285           }
286         else
287           {
288             GError *err = NULL;
289             utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
290             if ( NULL == utf8)
291               {
292                 g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
293                            local_encoding,
294                            err->message);
295                 g_clear_error (&err);
296               }
297           }
298
299         if ( NULL != utf8)
300           {
301             GError *err = NULL;
302             filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
303             if ( NULL == filename)
304               {
305                 g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
306                            err->message);
307                 g_clear_error (&err);
308               }
309           }
310
311         g_free (utf8);
312
313         if ( filename == NULL)
314           filename = xstrdup (arg);
315
316         psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
317
318         g_free (filename);
319         break;
320       }
321     default:
322       return ARGP_ERR_UNKNOWN;
323     }
324   return 0;
325 }
326
327
328 const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};