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