1c04e93b72244a8e5001c921d57dc1acf9cda60f
[pspp-builds.git] / src / ui / gui / psppire.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2004, 2005, 2006, 2009, 2010  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 "ui/gui/psppire.h"
20
21 #include <assert.h>
22 #include <gsl/gsl_errno.h>
23 #include <gtk/gtk.h>
24 #include <libintl.h>
25 #include <unistd.h>
26
27 #include "data/casereader.h"
28 #include "data/datasheet.h"
29 #include "data/file-handle-def.h"
30 #include "data/file-name.h"
31 #include "data/por-file-reader.h"
32 #include "data/procedure.h"
33 #include "data/settings.h"
34 #include "data/sys-file-reader.h"
35 #include "language/lexer/lexer.h"
36 #include "language/syntax-string-source.h"
37 #include "libpspp/getl.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/version.h"
41 #include "output/driver.h"
42 #include "output/journal.h"
43 #include "ui/gui/dict-display.h"
44 #include "ui/gui/executor.h"
45 #include "ui/gui/message-dialog.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-output-window.h"
50 #include "ui/gui/psppire-selector.h"
51 #include "ui/gui/psppire-var-store.h"
52 #include "ui/gui/psppire-var-view.h"
53 #include "ui/gui/psppire-window-register.h"
54 #include "ui/gui/psppire.h"
55 #include "ui/gui/widgets.h"
56 #include "ui/source-init-opts.h"
57 #include "ui/syntax-gen.h"
58
59 #include "gl/xalloc.h"
60 #include "gl/relocatable.h"
61
62 GtkRecentManager *the_recent_mgr = 0;
63 PsppireDataStore *the_data_store = 0;
64 PsppireVarStore *the_var_store = 0;
65
66 static void create_icon_factory (void);
67
68 struct source_stream *the_source_stream ;
69 struct dataset * the_dataset = NULL;
70
71 static GtkWidget *the_data_window;
72
73 static void load_data_file (const char *);
74
75 static void
76 replace_casereader (struct casereader *s)
77 {
78   psppire_data_store_set_reader (the_data_store, s);
79 }
80
81 #define _(msgid) gettext (msgid)
82 #define N_(msgid) msgid
83
84
85
86
87 void
88 initialize (struct source_stream *ss, const char *data_file)
89 {
90   PsppireDict *dictionary = 0;
91
92   i18n_init ();
93
94   preregister_widgets ();
95
96   gsl_set_error_handler_off ();
97   settings_init (&viewer_width, &viewer_length);
98   fh_init ();
99
100   the_dataset = create_dataset ();
101
102   message_dialog_init (the_source_stream);
103   the_source_stream = ss;
104
105   dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
106
107   bind_textdomain_codeset (PACKAGE, "UTF-8");
108
109   /* Create the model for the var_sheet */
110   the_var_store = psppire_var_store_new (dictionary);
111
112   the_data_store = psppire_data_store_new (dictionary);
113   replace_casereader (NULL);
114
115   create_icon_factory ();
116
117   psppire_output_window_setup ();
118
119   journal_enable ();
120   textdomain (PACKAGE);
121
122
123   the_recent_mgr = gtk_recent_manager_get_default ();
124
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
129   the_data_window = psppire_data_window_new ();
130   if (data_file != NULL)
131     load_data_file (data_file);
132
133   execute_syntax (create_syntax_string_source (""));
134
135   gtk_widget_show (the_data_window);
136 }
137
138
139 void
140 de_initialize (void)
141 {
142   destroy_source_stream (the_source_stream);
143   message_dialog_done ();
144   settings_done ();
145   output_close ();
146   i18n_done ();
147 }
148
149
150 static void
151 func (gpointer key, gpointer value, gpointer data)
152 {
153   gboolean rv;
154   PsppireWindow *window = PSPPIRE_WINDOW (value);
155
156   g_signal_emit_by_name (window, "delete-event", 0, &rv);
157 }
158
159 void
160 psppire_quit (void)
161 {
162   PsppireWindowRegister *reg = psppire_window_register_new ();
163   psppire_window_register_foreach (reg, func, NULL);
164
165   gtk_main_quit ();
166 }
167
168
169 struct icon_info
170 {
171   const char *file_name;
172   const gchar *id;
173 };
174
175
176 static const struct icon_info icons[] =
177   {
178     {PKGDATADIR "/value-labels.png",    "pspp-value-labels"},
179     {PKGDATADIR "/weight-cases.png",    "pspp-weight-cases"},
180     {PKGDATADIR "/goto-variable.png",   "pspp-goto-variable"},
181     {PKGDATADIR "/insert-variable.png", "pspp-insert-variable"},
182     {PKGDATADIR "/insert-case.png",     "pspp-insert-case"},
183     {PKGDATADIR "/split-file.png",      "pspp-split-file"},
184     {PKGDATADIR "/select-cases.png",    "pspp-select-cases"},
185     {PKGDATADIR "/recent-dialogs.png",  "pspp-recent-dialogs"},
186     {PKGDATADIR "/nominal.png",         "var-nominal"},
187     {PKGDATADIR "/ordinal.png",         "var-ordinal"},
188     {PKGDATADIR "/scale.png",           "var-scale"},
189     {PKGDATADIR "/string.png",          "var-string"},
190     {PKGDATADIR "/date-scale.png",      "var-date-scale"}
191   };
192
193 static void
194 create_icon_factory (void)
195 {
196   gint i;
197   GtkIconFactory *factory = gtk_icon_factory_new ();
198
199   for (i = 0 ; i < sizeof (icons) / sizeof(icons[0]); ++i)
200     {
201       GError *err = NULL;
202       GdkPixbuf *pixbuf =
203         gdk_pixbuf_new_from_file (relocate (icons[i].file_name), &err);
204
205       if ( pixbuf )
206         {
207           GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
208           g_object_unref (pixbuf);
209           gtk_icon_factory_add ( factory, icons[i].id, icon_set);
210         }
211       else
212         {
213           g_warning ("Cannot create icon: %s", err->message);
214           g_clear_error (&err);
215         }
216     }
217
218   {
219     /* Create our own "pspp-stock-reset" item, using the
220        GTK_STOCK_REFRESH icon set */
221
222     GtkStockItem items[] = {
223       {"pspp-stock-reset", N_("_Reset"), 0, 0, PACKAGE},
224       {"pspp-stock-select", N_("_Select"), 0, 0, PACKAGE}
225     };
226
227
228     gtk_stock_add (items, 2);
229     gtk_icon_factory_add (factory, "pspp-stock-reset",
230                           gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH)
231                           );
232
233     gtk_icon_factory_add (factory, "pspp-stock-select",
234                           gtk_icon_factory_lookup_default (GTK_STOCK_INDEX)
235                           );
236   }
237
238   gtk_icon_factory_add_default (factory);
239 }
240 \f
241 static void
242 load_data_file (const char *arg)
243 {
244   gchar *filename = NULL;
245   gchar *utf8 = NULL;
246   const gchar *local_encoding = NULL;
247   gsize written = -1;
248   const gboolean local_is_utf8 = g_get_charset (&local_encoding);
249
250   /* There seems to be no Glib function to convert from local encoding
251      to filename encoding.  Therefore it has to be done in two steps:
252      the intermediate encoding is UTF8.
253
254      Either step could fail.  However, in many cases the file can still
255      be loaded even if the conversion fails. So in those cases, after showing
256      a warning, we simply copy the locally encoded filename to the destination
257      and hope for the best.
258   */
259
260   if ( local_is_utf8)
261     {
262       utf8 = xstrdup (arg);
263     }
264   else
265     {
266       GError *err = NULL;
267       utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
268       if ( NULL == utf8)
269         {
270           g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
271                      local_encoding,
272                      err->message);
273           g_clear_error (&err);
274         }
275     }
276
277   if ( NULL != utf8)
278     {
279       GError *err = NULL;
280       filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
281       if ( NULL == filename)
282         {
283           g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
284                      err->message);
285           g_clear_error (&err);
286         }
287     }
288
289   g_free (utf8);
290
291   if ( filename == NULL)
292     filename = xstrdup (arg);
293
294   psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
295
296   g_free (filename);
297 }