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