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