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