gui: Avoid creating empty output window at startup time.
[pspp] / src / ui / gui / psppire.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011  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 #include <assert.h>
20 #include <gsl/gsl_errno.h>
21 #include <gtk/gtk.h>
22 #include <libintl.h>
23 #include <unistd.h>
24
25 #include "data/casereader.h"
26 #include "data/dataset.h"
27 #include "data/datasheet.h"
28 #include "data/file-handle-def.h"
29 #include "data/file-name.h"
30 #include "data/por-file-reader.h"
31 #include "data/session.h"
32 #include "data/settings.h"
33 #include "data/sys-file-reader.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-selector.h"
52 #include "ui/gui/psppire-var-store.h"
53 #include "ui/gui/psppire-var-view.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 "gl/configmake.h"
60 #include "gl/xalloc.h"
61 #include "gl/relocatable.h"
62
63 GtkRecentManager *the_recent_mgr;
64
65 static void inject_renamed_icons (void);
66 static void create_icon_factory (void);
67 static void load_data_file (PsppireDataWindow *, const char *);
68
69 #define _(msgid) gettext (msgid)
70 #define N_(msgid) msgid
71
72
73 void
74 initialize (const char *data_file)
75 {
76   PsppireDataWindow *data_window;
77
78   i18n_init ();
79
80   preregister_widgets ();
81
82   gsl_set_error_handler_off ();
83   settings_init ();
84   fh_init ();
85
86   psppire_set_lexer (NULL);
87
88   bind_textdomain_codeset (PACKAGE, "UTF-8");
89
90   inject_renamed_icons ();
91   create_icon_factory ();
92
93   psppire_output_window_setup ();
94
95   journal_enable ();
96   textdomain (PACKAGE);
97
98
99   the_recent_mgr = gtk_recent_manager_get_default ();
100
101   psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry);
102   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
103   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
104
105   data_window = psppire_default_data_window ();
106   if (data_file != NULL)
107     load_data_file (data_window, data_file);
108 }
109
110
111 void
112 de_initialize (void)
113 {
114   settings_done ();
115   output_close ();
116   i18n_done ();
117 }
118
119 static void
120 func (gpointer key, gpointer value, gpointer data)
121 {
122   gboolean rv;
123   PsppireWindow *window = PSPPIRE_WINDOW (value);
124
125   g_signal_emit_by_name (window, "delete-event", 0, &rv);
126 }
127
128 void
129 psppire_quit (void)
130 {
131   PsppireWindowRegister *reg = psppire_window_register_new ();
132   psppire_window_register_foreach (reg, func, NULL);
133
134   gtk_main_quit ();
135 }
136
137 static void
138 inject_renamed_icon (const char *icon, const char *substitute)
139 {
140   GtkIconTheme *theme = gtk_icon_theme_get_default ();
141   if (!gtk_icon_theme_has_icon (theme, icon)
142       && gtk_icon_theme_has_icon (theme, substitute))
143     {
144       gint *sizes = gtk_icon_theme_get_icon_sizes (theme, substitute);
145       gint *p;
146
147       for (p = sizes; *p != 0; p++)
148         {
149           gint size = *p;
150           GdkPixbuf *pb;
151
152           pb = gtk_icon_theme_load_icon (theme, substitute, size, 0, NULL);
153           if (pb != NULL)
154             {
155               GdkPixbuf *copy = gdk_pixbuf_copy (pb);
156               if (copy != NULL)
157                 gtk_icon_theme_add_builtin_icon (icon, size, copy);
158             }
159         }
160     }
161 }
162
163 /* Avoid a bug in GTK+ 2.22 that can cause a segfault at startup time.  Earlier
164    and later versions of GTK+ do not have the bug.  Bug #31511.
165
166    Based on this patch against Inkscape:
167    https://launchpadlibrarian.net/60175914/copy_renamed_icons.patch */
168 static void
169 inject_renamed_icons (void)
170 {
171   if (gtk_major_version == 2 && gtk_minor_version == 22)
172     {
173       inject_renamed_icon ("gtk-file", "document-x-generic");
174       inject_renamed_icon ("gtk-directory", "folder");
175     }
176 }
177
178 struct icon_info
179 {
180   const char *file_name;
181   const gchar *id;
182 };
183
184
185 static const struct icon_info icons[] =
186   {
187     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
188     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
189     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
190     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
191     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
192     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
193     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
194     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
195     {PKGDATADIR "/nominal.png",         "var-nominal"},
196     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
197     {PKGDATADIR "/scale.png",           "var-scale"},
198     {PKGDATADIR "/string.png",          "var-string"},
199     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
200   };
201
202 static void
203 create_icon_factory (void)
204 {
205   gint i;
206   GtkIconFactory *factory = gtk_icon_factory_new ();
207
208   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
209     {
210       GError *err = NULL;
211       GdkPixbuf *pixbuf =
212         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
213
214       if ( pixbuf )
215         {
216           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
217           g_object_unref (pixbuf);
218           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
219         }
220       else
221         {
222           g_warning ("Cannot create icon: %s", err->message);
223           g_clear_error (&err);
224         }
225     }
226
227   {
228     /* Create our own "pspp-stock-reset" item, using the
229        GTK_STOCK_REFRESH icon set */
230
231     GtkStockItem items[] = {
232       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
233       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
234     };
235
236
237     gtk_stock_add (items, 2);
238     gtk_icon_factory_add (factory, "pspp-stock-reset",
239                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
240                           );
241
242     gtk_icon_factory_add (factory, "pspp-stock-select",
243                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
244                           );
245   }
246
247   gtk_icon_factory_add_default (factory);
248 }
249 \f
250 static void
251 load_data_file (PsppireDataWindow *window, const char *arg)
252 {
253   gchar *filename = NULL;
254   gchar *utf8 = NULL;
255   const gchar *local_encoding = NULL;
256   gsize written = -1;
257   const gboolean local_is_utf8 = g_get_charset (&local_encoding);
258
259   /* There seems to be no Glib function to convert from local encoding
260      to filename encoding.  Therefore it has to be done in two steps:
261      the intermediate encoding is UTF8.
262
263      Either step could fail.  However, in many cases the file can still
264      be loaded even if the conversion fails. So in those cases, after showing
265      a warning, we simply copy the locally encoded filename to the destination
266      and hope for the best.
267   */
268
269   if ( local_is_utf8)
270     {
271       utf8 = xstrdup (arg);
272     }
273   else
274     {
275       GError *err = NULL;
276       utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
277       if ( NULL == utf8)
278         {
279           g_warning ("Cannot convert filename from local encoding `%s' to UTF-8: %s",
280                      local_encoding,
281                      err->message);
282           g_clear_error (&err);
283         }
284     }
285
286   if ( NULL != utf8)
287     {
288       GError *err = NULL;
289       filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
290       if ( NULL == filename)
291         {
292           g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
293                      err->message);
294           g_clear_error (&err);
295         }
296     }
297
298   g_free (utf8);
299
300   if ( filename == NULL)
301     filename = xstrdup (arg);
302
303   psppire_window_load (PSPPIRE_WINDOW (window), filename);
304
305   g_free (filename);
306 }
307
308 static void
309 handle_msg (const struct msg *m_, void *lexer_)
310 {
311   struct lexer *lexer = lexer_;
312   struct msg m = *m_;
313
314   if (lexer != NULL && m.file_name == NULL)
315     {
316       m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
317       m.first_line = lex_get_first_line_number (lexer, 0);
318       m.last_line = lex_get_last_line_number (lexer, 0);
319       m.first_column = lex_get_first_column (lexer, 0);
320       m.last_column = lex_get_last_column (lexer, 0);
321     }
322
323   message_item_submit (message_item_create (&m));
324 }
325
326 void
327 psppire_set_lexer (struct lexer *lexer)
328 {
329   msg_set_handler (handle_msg, lexer);
330 }