output: Make it possible to push and pop output engines.
[pspp] / src / ui / gui / psppire.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011, 2012, 2013, 2014  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
20 #include <assert.h>
21 #include <gsl/gsl_errno.h>
22 #include <gtk/gtk.h>
23 #include <libintl.h>
24 #include <unistd.h>
25
26 #include "data/any-reader.h"
27 #include "data/casereader.h"
28 #include "data/dataset.h"
29 #include "data/datasheet.h"
30 #include "data/file-handle-def.h"
31 #include "data/file-name.h"
32 #include "data/por-file-reader.h"
33 #include "data/session.h"
34 #include "data/settings.h"
35 #include "data/sys-file-reader.h"
36
37 #include "language/lexer/lexer.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/version.h"
41
42 #include "output/driver.h"
43 #include "output/journal.h"
44 #include "output/message-item.h"
45
46 #include "ui/gui/dict-display.h"
47 #include "ui/gui/executor.h"
48 #include "ui/gui/psppire-data-store.h"
49 #include "ui/gui/psppire-data-window.h"
50 #include "ui/gui/psppire-dict.h"
51 #include "ui/gui/psppire.h"
52 #include "ui/gui/psppire-output-window.h"
53 #include "ui/gui/psppire-syntax-window.h"
54 #include "ui/gui/psppire-selector.h"
55 #include "ui/gui/psppire-var-view.h"
56 #include "ui/gui/psppire-means-layer.h"
57 #include "ui/gui/psppire-window-register.h"
58 #include "ui/gui/widgets.h"
59 #include "ui/source-init-opts.h"
60 #include "ui/syntax-gen.h"
61
62 #include "ui/gui/icons/icon-names.h"
63
64
65 #include "gl/configmake.h"
66 #include "gl/xalloc.h"
67 #include "gl/relocatable.h"
68
69 static void create_icon_factory (void);
70 static gchar *local_to_filename_encoding (const char *fn);
71
72
73 #define _(msgid) gettext (msgid)
74 #define N_(msgid) msgid
75
76
77 void
78 initialize (const char *data_file)
79 {
80   i18n_init ();
81
82   preregister_widgets ();
83
84   gsl_set_error_handler_off ();
85   output_engine_push ();
86   settings_init ();
87   fh_init ();
88
89   psppire_set_lexer (NULL);
90
91   bind_textdomain_codeset (PACKAGE, "UTF-8");
92
93   create_icon_factory ();
94
95   psppire_output_window_setup ();
96
97   journal_init ();
98   textdomain (PACKAGE);
99
100   /* FIXME: This should be implemented with a GtkInterface */
101   psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry);
102   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
103   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
104   psppire_selector_set_default_selection_func (PSPPIRE_TYPE_MEANS_LAYER, insert_source_row_into_layers);
105
106   if (data_file)
107     {
108       gchar *filename = local_to_filename_encoding (data_file);
109
110       enum detect_result res = any_reader_may_open (filename);
111
112       /* Check to see if the file is a .sav or a .por file.  If not
113          assume that it is a syntax file */
114       if (res == ANY_YES)
115         open_data_window (NULL, filename, NULL, NULL);
116       else if (res == ANY_NO)
117         {
118           create_data_window ();
119           open_syntax_window (filename, NULL);
120         }
121
122       g_free (filename);
123     }
124   else
125     create_data_window ();
126 }
127
128
129 void
130 de_initialize (void)
131 {
132   settings_done ();
133   output_engine_pop ();
134   i18n_done ();
135 }
136
137 static void
138 func (gpointer key, gpointer value, gpointer data)
139 {
140   gboolean rv;
141   PsppireWindow *window = PSPPIRE_WINDOW (value);
142
143   g_signal_emit_by_name (window, "delete-event", 0, &rv);
144 }
145
146 void
147 psppire_quit (void)
148 {
149   PsppireWindowRegister *reg = psppire_window_register_new ();
150   psppire_window_register_foreach (reg, func, NULL);
151
152   gtk_main_quit ();
153 }
154
155 struct icon_size
156 {
157   int resolution;  /* The dimension of the images which will be used */
158   size_t n_sizes;  /* The number of items in the array below. */
159   const GtkIconSize *usage; /* An array determining for what the icon set is used */
160 };
161
162 static const GtkIconSize menus[] = {GTK_ICON_SIZE_MENU};
163 static const GtkIconSize large_toolbar[] = {GTK_ICON_SIZE_LARGE_TOOLBAR};
164 static const GtkIconSize small_toolbar[] = {GTK_ICON_SIZE_SMALL_TOOLBAR};
165
166
167 /* We currently have three icon sets viz: 16x16, 24x24 and 32x32
168    We use the 16x16 for menus, the 32x32 for the large_toolbars and 
169    the 24x24 for small_toolbars.
170
171    The order of this array is pertinent.  The icons in the sets occuring
172    earlier in the array will be used a the wildcard (default) icon size,
173    if such an icon exists.
174 */
175 static const struct icon_size sizemap[] = 
176 {
177   {24,  sizeof (small_toolbar) / sizeof (GtkIconSize), small_toolbar},
178   {16,  sizeof (menus) / sizeof (GtkIconSize), menus},
179   {32,  sizeof (large_toolbar) / sizeof (GtkIconSize), large_toolbar}
180 };
181
182
183 static void
184 create_icon_factory (void)
185 {
186   gint c;
187   GtkIconFactory *factory = gtk_icon_factory_new ();
188   struct icon_context ctx[2];
189   ctx[0] = action_icon_context;
190   ctx[1] = category_icon_context;
191   for (c = 0 ; c < 2 ; ++c)
192   {
193     const struct icon_context *ic = &ctx[c];
194     gint i;
195     for (i = 0 ; i < ic->n_icons ; ++i)
196       {
197         gboolean wildcarded = FALSE;
198         GtkIconSet *icon_set = gtk_icon_set_new ();
199         int r;
200         for (r = 0 ; r < sizeof (sizemap) / sizeof (sizemap[0]); ++r)
201           {
202             int s;
203             GtkIconSource *source = gtk_icon_source_new ();
204             gchar *filename = g_strdup_printf ("%s/%s/%dx%d/%s.png", PKGDATADIR,
205                                                ic->context_name,
206                                                sizemap[r].resolution, sizemap[r].resolution,
207                                                ic->icon_name[i]);
208             const char *relocated_filename = relocate (filename);
209             GFile *gf = g_file_new_for_path (relocated_filename);
210             if (g_file_query_exists (gf, NULL))
211               {
212                 gtk_icon_source_set_filename (source, relocated_filename);
213                 if (!wildcarded)
214                   {
215                     gtk_icon_source_set_size_wildcarded (source, TRUE);
216                     wildcarded = TRUE;
217                   }
218               }
219             g_object_unref (gf);
220
221             for (s = 0 ; s < sizemap[r].n_sizes ; ++s)
222               gtk_icon_source_set_size (source, sizemap[r].usage[s]);
223             if (filename != relocated_filename)
224               free (CONST_CAST (char *, relocated_filename));
225             g_free (filename);
226
227             if ( gtk_icon_source_get_filename (source))
228               gtk_icon_set_add_source (icon_set, source);
229           }
230       
231         gtk_icon_factory_add (factory, ic->icon_name[i], icon_set);
232     }
233   }
234
235   {
236     struct iconmap
237     {
238       const gchar *gtk_id;
239       gchar *pspp_id;
240     };
241
242     /* We have our own icons for some things.
243        But we want the Stock Item to be identical to the Gtk standard
244        ones in all other respects.
245     */
246     const struct iconmap map[] = {
247       {GTK_STOCK_NEW,    "file-new-document"},
248       {GTK_STOCK_QUIT,   "file-quit"},
249       {GTK_STOCK_SAVE,   "file-save-document"},
250       {GTK_STOCK_CUT,    "edit-cut"},
251       {GTK_STOCK_COPY,   "edit-copy"},
252       {GTK_STOCK_PASTE,  "edit-paste"},
253       {GTK_STOCK_UNDO,   "edit-undo"},
254       {GTK_STOCK_REDO,   "edit-redo"},
255       {GTK_STOCK_DELETE, "edit-delete"},
256       {GTK_STOCK_ABOUT,  "help-about"},
257       {GTK_STOCK_PRINT,  "file-print-document"}
258     };
259
260     GtkStockItem customised[sizeof (map) / sizeof (map[0])];
261     int i;
262
263     for (i = 0; i < sizeof (map) / sizeof (map[0]); ++i)
264     {
265       gtk_stock_lookup (map[i].gtk_id, &customised[i]);
266       customised[i].stock_id =  map[i].pspp_id;
267     }
268
269
270
271     gtk_stock_add (customised, sizeof (map) / sizeof (map[0]));
272   }
273
274   {
275     /* Create our own "pspp-stock-reset" item, using the
276        GTK_STOCK_REFRESH icon set */
277     GtkStockItem items[2] = {
278       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
279       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
280     };
281
282     gtk_stock_add (items, 2);
283
284     gtk_icon_factory_add (factory, "pspp-stock-reset",
285                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
286                           );
287
288     gtk_icon_factory_add (factory, "pspp-stock-select",
289                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
290                           );
291   }
292
293   gtk_icon_factory_add_default (factory);
294 }
295 \f
296 /* 
297    Convert a filename from the local encoding into "filename" encoding.
298    The return value will be allocated on the heap.  It is the responsibility
299    of the caller to free it.
300  */
301 static gchar *
302 local_to_filename_encoding (const char *fn)
303 {
304   gchar *filename = NULL;
305   gchar *utf8 = NULL;
306   const gchar *local_encoding = NULL;
307   gsize written = -1;
308   const gboolean local_is_utf8 = g_get_charset (&local_encoding);
309
310   /* There seems to be no Glib function to convert from local encoding
311      to filename encoding.  Therefore it has to be done in two steps:
312      the intermediate encoding is UTF8.
313
314      Either step could fail.  However, in many cases the file can still
315      be loaded even if the conversion fails. So in those cases, after showing
316      a warning, we simply copy the locally encoded filename to the destination
317      and hope for the best.
318   */
319
320   if ( local_is_utf8)
321     {
322       utf8 = xstrdup (fn);
323     }
324   else
325     {
326       GError *err = NULL;
327       utf8 = g_locale_to_utf8 (fn, -1, NULL, &written, &err);
328       if ( NULL == utf8)
329         {
330           g_warning ("Cannot convert filename from local encoding `%s' to UTF-8: %s",
331                      local_encoding,
332                      err->message);
333           g_clear_error (&err);
334         }
335     }
336
337   if ( NULL != utf8)
338     {
339       GError *err = NULL;
340       filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
341       if ( NULL == filename)
342         {
343           g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
344                      err->message);
345           g_clear_error (&err);
346         }
347     }
348
349   g_free (utf8);
350
351   if ( filename == NULL)
352     filename = xstrdup (fn);
353
354   return filename;
355 }
356
357 static void
358 handle_msg (const struct msg *m_, void *lexer_)
359 {
360   struct lexer *lexer = lexer_;
361   struct msg m = *m_;
362
363   if (lexer != NULL && m.file_name == NULL)
364     {
365       m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
366       m.first_line = lex_get_first_line_number (lexer, 0);
367       m.last_line = lex_get_last_line_number (lexer, 0);
368       m.first_column = lex_get_first_column (lexer, 0);
369       m.last_column = lex_get_last_column (lexer, 0);
370     }
371
372   message_item_submit (message_item_create (&m));
373 }
374
375 void
376 psppire_set_lexer (struct lexer *lexer)
377 {
378   msg_set_handler (handle_msg, lexer);
379 }