ed6d29a3150606d5c42d46357a27e48f6a93a798
[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             gtk_icon_source_free (source);
266           }
267       
268         gtk_icon_factory_add (factory, ic->icon_name[i], icon_set);
269     }
270   }
271
272   {
273     struct iconmap
274     {
275       const gchar *gtk_id;
276       gchar *pspp_id;
277     };
278
279     /* We have our own icons for some things.
280        But we want the Stock Item to be identical to the Gtk standard
281        ones in all other respects.
282     */
283     const struct iconmap map[] = {
284       {GTK_STOCK_NEW,    "file-new-document"},
285       {GTK_STOCK_QUIT,   "file-quit"},
286       {GTK_STOCK_SAVE,   "file-save-document"},
287       {GTK_STOCK_CUT,    "edit-cut"},
288       {GTK_STOCK_COPY,   "edit-copy"},
289       {GTK_STOCK_PASTE,  "edit-paste"},
290       {GTK_STOCK_UNDO,   "edit-undo"},
291       {GTK_STOCK_REDO,   "edit-redo"},
292       {GTK_STOCK_DELETE, "edit-delete"},
293       {GTK_STOCK_ABOUT,  "help-about"},
294       {GTK_STOCK_PRINT,  "file-print-document"}
295     };
296
297     GtkStockItem customised[sizeof (map) / sizeof (map[0])];
298     int i;
299
300     for (i = 0; i < sizeof (map) / sizeof (map[0]); ++i)
301     {
302       gtk_stock_lookup (map[i].gtk_id, &customised[i]);
303       customised[i].stock_id =  map[i].pspp_id;
304     }
305
306
307
308     gtk_stock_add (customised, sizeof (map) / sizeof (map[0]));
309   }
310
311   {
312     /* Create our own "pspp-stock-reset" item, using the
313        GTK_STOCK_REFRESH icon set */
314     GtkStockItem items[2] = {
315       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
316       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
317     };
318
319     gtk_stock_add (items, 2);
320
321     gtk_icon_factory_add (factory, "pspp-stock-reset",
322                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
323                           );
324
325     gtk_icon_factory_add (factory, "pspp-stock-select",
326                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
327                           );
328   }
329
330   gtk_icon_factory_add_default (factory);
331 }
332 \f
333 /* 
334    Convert a filename from the local encoding into "filename" encoding.
335    The return value will be allocated on the heap.  It is the responsibility
336    of the caller to free it.
337  */
338 static gchar *
339 local_to_filename_encoding (const char *fn)
340 {
341   gchar *filename = NULL;
342   gchar *utf8 = NULL;
343   const gchar *local_encoding = NULL;
344   gsize written = -1;
345   const gboolean local_is_utf8 = g_get_charset (&local_encoding);
346
347   /* There seems to be no Glib function to convert from local encoding
348      to filename encoding.  Therefore it has to be done in two steps:
349      the intermediate encoding is UTF8.
350
351      Either step could fail.  However, in many cases the file can still
352      be loaded even if the conversion fails. So in those cases, after showing
353      a warning, we simply copy the locally encoded filename to the destination
354      and hope for the best.
355   */
356
357   if ( local_is_utf8)
358     {
359       utf8 = xstrdup (fn);
360     }
361   else
362     {
363       GError *err = NULL;
364       utf8 = g_locale_to_utf8 (fn, -1, NULL, &written, &err);
365       if ( NULL == utf8)
366         {
367           g_warning ("Cannot convert filename from local encoding `%s' to UTF-8: %s",
368                      local_encoding,
369                      err->message);
370           g_clear_error (&err);
371         }
372     }
373
374   if ( NULL != utf8)
375     {
376       GError *err = NULL;
377       filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
378       if ( NULL == filename)
379         {
380           g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
381                      err->message);
382           g_clear_error (&err);
383         }
384     }
385
386   g_free (utf8);
387
388   if ( filename == NULL)
389     filename = xstrdup (fn);
390
391   return filename;
392 }
393
394 static void
395 handle_msg (const struct msg *m_, void *lexer_)
396 {
397   struct lexer *lexer = lexer_;
398   struct msg m = *m_;
399
400   if (lexer != NULL && m.file_name == NULL)
401     {
402       m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
403       m.first_line = lex_get_first_line_number (lexer, 0);
404       m.last_line = lex_get_last_line_number (lexer, 0);
405       m.first_column = lex_get_first_column (lexer, 0);
406       m.last_column = lex_get_last_column (lexer, 0);
407     }
408
409   message_item_submit (message_item_create (&m));
410 }
411
412 void
413 psppire_set_lexer (struct lexer *lexer)
414 {
415   msg_set_handler (handle_msg, lexer);
416 }