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